Scripts and aliases for your linux
Every person who spends more than five minutes in a terminal runs into the same thing: the same long commands have to be typed over and over, and routine actions eat up time and attention. At first you put up with it, then you start optimizing.
A simple alias in .bashrc or .zshrc feels like a small revelation. The first working script saved in ~/.local/bin feels like a breakthrough. It’s not just about laziness — it’s about efficiency, about workflow optimization.
Over time, such "micro-optimizations" accumulate into an entire personal framework or a set of command-line utilities. It is no longer a couple of patches, but your own environment, honed for specific tasks. In this article, I want to showcase my collection of such scripts and aliases — not as an ideal standard, but as an example of a living approach. Perhaps some solutions will prove useful to you as well, and most importantly — they will inspire you to create something of your own, even more convenient.
Quite often in the Linux community, you can see a discussion on when aliases are useful and when executable scripts in a conventional ~/.local/bin/ directory are preferable. Aliases are compact and fast, and thanks to that, they can replace small command chains. However, they have drawbacks: for example, if you define them in the shell config, you have to reload the session. Therefore, sometimes it's more convenient to use scripts, since they can be written not only in bash but also in other programming languages available in the system. And, naturally, scripts offer a much wider scope for activity.
In this article, I’ll show both aliases and scripts that I use on a daily basis.
All scripts are available in my repository. You can share your own scripts in the comments or via a pull request.
❯ NixOS
Let's start with a set of aliases for NixOS:
alias rb="sudo nixos-rebuild switch --flake /home/alexeev/nixos/"
alias upd="nix flake update /home/alexeev/nixos/"
alias upg="sudo nixos-rebuild switch --upgrade --flake /home/alexeev/nixos/"
alias nixclean="sudo nix-collect-garbage -d"
alias hms="home-manager switch --flake /home/alexeev/nixos/"
alias conf="nvim ~/nixos/nixos/configuration.nix"
alias pkgs="nvim ~/nixos/nixos/packages.nix"
This allows for rebuilding, updating, cleaning the system, as well as quickly working with the configuration and packages in the system.
❯ Git
Aliases for git can be made both via the standard external approach:
alias gga="git add"
alias ggc="git commit"
alias ggcm="git commit -m"
alias ggs="git status"
alias ggl="git log"
alias gglo="git log --oneline"
alias ggd="git diff"
alias ggds="git diff --staged"
alias ggr="git restore"
As well as through configuring the ~/.gitconfig file:
[alias]
st = status -b
c = commit
co = checkout
br = branch
slog = log --pretty=format:"%C(auto)%h%C(auto)%d\\ %C(auto,reset)%s\\ \\ [%C(auto,blue)%an%C(auto,reset),\\ %C(auto,cyan)%ar%C(auto,reset)]"
glog = log --graph --pretty=format:"%C(auto,yellow)%h%C(auto)%d\\ %C(auto,reset)%s\\ \\ [%C(auto,blue)%an%C(auto,reset),\\ %C(auto,cyan)%ar%C(auto,reset)]"
wlog = log --pretty=format:"%C(auto,yellow)%h%C(auto)%d%C(auto,reset)\\ by\\ %C(auto,blue)%an%C(auto,reset),\\ %C(auto,cyan)%ar%C(auto,reset)%n\\ %s%n" --stat
gr = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
wt = worktree
I use these aliases quite often for quick work with repositories, retrieving logs and graphs of branches and commits.
I also sometimes use this interesting script:
#!/usr/bin/env python3
import os
import re
class GitVersion:
def __init__(self):
self._default_version = "0.1.0"
os.chdir(os.path.dirname(os.path.realpath(__file__)))
@property
def tag(self):
stream = os.popen("git describe --match v[0-9]* --abbrev=0 --tags")
return stream.read().strip()
@property
def version(self):
version = f"{self.tag[1:]}.{self.build}"
if version == ".":
return self._default_version
return version
@property
def default_branch(self):
stream = os.popen("git config --get init.defaultBranch")
result = stream.read().strip()
if not result:
result = "main"
return result
@property
def build(self):
stream = os.popen(f"git rev-list {self.tag}.. --count")
return stream.read().strip()
@property
def branch(self):
stream = os.popen("git branch --show-current")
return stream.read().strip()
@property
def full(self):
return f"{self.version}-{self.branch}"
@property
def standard(self):
standard = f"{self.version}-{self.branch}"
if self.branch == self.default_branch or re.match("release/.*", self.branch):
standard = f"{self.version}"
return standard
@property
def commit(self):
stream = os.popen("git rev-parse HEAD")
return stream.read().strip()
@property
def commit_hash(self):
stream = os.popen("git rev-parse --short HEAD")
return stream.read().strip()
def __str__(self):
return f"""
Tag: {self.tag}
Version: {self.version}
Full: {self.full}
Branch: {self.branch}
Build: {self.build}
Standard: {self.standard}
Commit: {self.commit}
GitRepo {self.full} {self.commit_hash}
"""
if __name__ == "__main__":
git_version = GitVersion()
print(git_version)
This script allows retrieving information about the repository, including release tags in a specific format (git describe --match v[0-9]* --abbrev=0 --tags). I personally use this script quite often when I need to coordinate work with a git repository. It uses the latest tag (vX.X.X) as the base version and adds the number of commits after the tag as the build number. For main/release branches, the version is displayed without the branch name; for others — with the branch name. If there are no tags, version 0.1.0 is used. The script is useful for CI/CD pipelines to automatically generate build versions.
❯ Useful Aliases
I frequently use aliases for my shell. For example, I replaced ls with the exa utility via alias ls='exa --icons'.
alias ll="ls -l"
alias se="sudoedit"
alias bat="bat --theme base16"
alias ff=fastfetch
alias nv=nvim
alias v=vim
alias nixfish="echo Enter to nix-shell && nix-shell . --command fish"
alias ..='cd ..'
alias 2..='cd ../..'
alias 3..='cd ../../..'
alias 4..='cd ../../../..'
alias 5..='cd ../../../../..'
I use the nixfish command when I need to enter a nix-shell environment through the fish command shell (since I use it on a regular basis). The rest are convenient command shortcuts, from program invocations to simplifying commands (as seen in the last block, which navigates to previous directories).
I also use the following:
alias syslog_emerg="sudo dmesg --level=emerg,alert,crit"
alias syslog="sudo dmesg --level=err,warn"
alias xlog='grep "(EE)\|(WW)\|error\|failed" ~/.local/share/xorg/Xorg.0.log'
alias vacuum="sudo journalctl --vacuum-size=100M"
alias vacuum_time="sudo journalctl --vacuum-time=2weeks"
alias rm="rmtrash "
alias youtube='yt-dlp -f "bestvideo[height<=1080]+bestaudio" --merge-output-format mp4 --output "%(title)s.%(ext)s"'
alias youtubemp3='yt-dlp -x --audio-format mp3 --output "%(title)s_audio.%(ext)s"'
The first 5, as you can see, help interact with kernel messages and the journal, as well as clean them up. I replace the rm command with the rmtrash utility, which moves the deleted file to the trash. This has saved me from losing files more than once. The youtube command helps download videos via yt-dlp in the format I need, while youtubemp3 saves YouTube audio in mp3 format.
❯ Bash Scripts for Various Use Cases
Bash scripts allow for implementing more complex or customizable logic.
For example, the script tempe.sh creates a temporary directory and navigates into it.
And the scripts check-cpu.sh and check-gpu.sh allow retrieving the CPU and GPU vendor, respectively. I use these scripts if, for example, I need to install drivers for a specific vendor.
Here, for instance, is the clean_broken_links.sh script:
#!/usr/bin/env bash
# Target directory for scan
TARGET_DIR="$HOME"
# Search and delete broken symlinks
find "$TARGET_DIR" -xtype l -print -delete
echo "✅ All broken symlinks deleted from $TARGET_DIR"
It recursively cleans a directory of broken symlinks, which helps keep the system tidy and prevents clutter.
Continuing the theme of cleanup and organization, one can mention the script clean_downloads_dir.py. It is written in Python and allows sorting a directory (by default ~/Downloads), and you can customize which file extensions go to which directory via an extensions.json file in the current directory. If it doesn't exist, it is created automatically and filled with default values. I personally use it often, and not only for the Downloads directory.
Back when I was still on Arch Linux, I wrote a small script for cleaning Arch (requires the pacman-contrib package for paccache):
#!/usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
PURPLE='\033[0;37m'
END='\033[0m'
printf "${GREEN}Cleaning...${END}\n"
printf "${RED}[+] Full system update${END}\n"
sudo pacman -Syu
printf "${BLUE}[+] Clean pacman cache${END}\n"
sudo pacman -Scc
sudo paccache -r
sudo paccache -rk1
sudo paccache -ruk0
printf "${CYAN}[+] Clean orphans${END}\n"
sudo pacman -Rns $(pacman -Qtdq)
printf "${PURPLE}[+] Clean font cache${END}\n"
fc-cache -frv
printf "${YELLOW}[+] Clean cache and tmp${END}\n"
sudo truncate -s 0 /var/log/pacman.log
sudo truncate -s 0 /var/log/pacman.log
rm -rf ~/.cache/
sudo rm -rf /tmp/*
printf "${GREEN}End!${END}\n"
Besides that, it's often useful to clean up old temporary files (delete_old_temp_files.sh):
#!/usr/bin/env bash
TARGET_DIR="/tmp"
MAX_AGE=7
find "$TARGET_DIR" -type f -mtime +$MAX_AGE -exec rm -v {} \;
echo "✅ Delete temporary files that are more $MAX_AGE days from $TARGET_DIR"
If I need to get a specific emoji, I use the script emoji.sh, which allows retrieving an emoji by name (emoji.sh smile).
Also, from this article, I adopted the following scripts into my system:
_mkcd foo_creates a directory and navigates into it viacd. Essentially, this is the commandmkdir foo && cd foo. I use this script constantly — almost every time I create a directory._mksh_allows quickly creating shell scripts. For example,mksh foo.shcreatesfoo.sh, makes it executable withchmod u+x, adds Bash prefixes, and opens the script in an editor (in my case, Vim). It comes in handy every few days. Many of the scripts listed in this article were created usingmksh._url "$my_url"_parses a URL into its component parts. I use it about once a month to get information about a URL, often simply because I don't want to click on a link with a tracker.
❯ Network Utilities
I have a whole set of scripts for network-related tasks:
- check_wifi_connection.sh — Tracks changes in the connected Wi-Fi network. The script identifies the current Wi-Fi network and notifies when it changes. Automatically saves the last SSID to
~/.last_ssidand logs changes to~/.wifi_changes.log. Use for monitoring roaming between access points. - check_wifi_status.sh — Checks internet availability via ping. Verifies connection to Google DNS (8.8.8.8) and notifies about connection loss/recovery. All events are logged to
~/.network_status.log. Run periodically via cron for continuous monitoring. - detect_network_changes.sh — Detects external IP address changes. Monitors the public IP via ifconfig.me every minute, captures changes, and sends notifications. Useful for tracking reconnections, ISP changes, or dynamic IPs. Logs to
~/.network_changes.log. - detect_new_devices_in_net.sh — Scans the local network for new devices. Uses arp-scan to discover MAC addresses, compares them against a saved list
~/.known_devices.txt, and notifies about new devices. Requiresarp-scaninstalled. Run periodically for home network security. - httpstatus.sh — An HTTP status code reference. Displays a complete list of codes from 100 to 511 with descriptions. Supports keyword search when passing arguments. Use as
./httpstatus.sh 404for a quick lookup or./httpstatus.shfor the full list. - list_of_wifi_nets.sh — Real-time monitoring of available Wi-Fi networks. Shows SSID, signal strength, and quality indicators, sorted by signal strength. Updates the list every 5 seconds. Uses
nmcli. Run when searching for the best access point. - monitoring_net_activity.sh — Real-time network traffic monitoring. Measures incoming (RX) and outgoing (TX) traffic speed on a specified interface (default wlo1), updating data every second. Displays speed in KB/s. Use for analyzing network load.
- network_analysis.sh — Comprehensive network state analysis of the system. Gathers interface statistics, counts connections by state, identifies the top 10 processes by network activity, shows non-standard open ports, and error statistics. Run for diagnosing network issues.
❯ Working with systemd
A long time ago, I wrote an article about working with systemd, where I included a wrapper script for systemd itself at the end. I have slightly improved and modified it — systemdwrapper.py.
usage: systemdwrapper.py [-h] {version,disable,enable,restart,stop,start,status,startuptime,failed,active,stats,chain,export} ...
Utility for managing systemd services and analyzing boot time
positional arguments:
{version,disable,enable,restart,stop,start,status,startuptime,failed,active,stats,chain,export}
Available commands
version Get systemd version
disable Disable a service
enable Enable a service
restart Restart a service
stop Stop a service
start Start a service
status Show service status
startuptime Analyze system and service startup time
failed Show failed services
active Show active services
stats Show system statistics
chain Analyze critical service chain
export Export report to JSON
options:
-h, --help show this help message and exit
For example, when run with the startuptime command, the script parses the output of commands and displays a result like this:
Boot Statistics:
Slowest service (3780.0ms): NetworkManager-wait-online.service
Fastest service (7.0ms): sys-kernel-config.mount
Arithmetic mean of service startup time: 159.9ms
Median service startup time: 44.0ms
Total startup time for all services: 11193.0ms
Services with startup time > 1000ms:
3780.0ms - NetworkManager-wait-online.service
Additionally, I have another auxiliary bash script slowest_services_to_launch.sh, which logs the top 10 slowest services to a log file:
#!/usr/bin/env bash
LOG_FILE="/var/log/boot_time.log"
echo "🕰 Analyze system startup time" | tee -a $LOG_FILE
BOOT_TIME=$(systemd-analyze)
BLAME=$(systemd-analyze blame | head -n 10)
{
echo "⏱️ $(date)"
echo "$BOOT_TIME"
echo "📌 Ten most slowest services:"
echo "$BLAME"
echo "-----------------------------"
} >> $LOG_FILE
echo "✅ Data saved." | tee -a $LOG_FILE
Continuing the topic of working with services, the script below might sometimes be useful. It allows restarting specific systemd services if they are not running:
#!/usr/bin/env bash
SERVICES=("nginx" "postgresql")
LOG_FILE="/var/log/systemd_healthcheck.log"
echo "🔍 Check services status... $(date)" | tee -a $LOG_FILE
for svc in "${SERVICES[@]}"; do
systemctl is-active --quiet "$svc"
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "❌ Service $svc does not worked. Restart him..." | tee -a $LOG_FILE
systemctl restart "$svc"
sleep 1
systemctl is-active --quiet "$svc" && echo "✅ $svc started now." | tee -a $LOG_FILE
else
echo "✔️ $svc is worked." | tee -a $LOG_FILE
fi
done
❯ Auto-mounting Drives
In minimal systems, or without a full-fledged DE, mounting sometimes has to be done manually. Specifically for this, I wrote the script auto_mount_devices.sh:
#!/usr/bin/env bash
MOUNT_DIR="$HOME/MOUNTED_DEVICE"
mkdir -p "$MOUNT_DIR"
DEVICE=$(lsblk -o NAME,TYPE,HOTPLUG | awk '$2 == "disk" && $3 == 1 {print $1}' | tail -n1)
if [ -n "$DEVICE" ]; then
PARTITION="/dev/${DEVICE}1"
mkdir -p "$MOUNT_DIR/$PARTITION"
sudo mount "$PARTITION" "$MOUNT_DIR/$PARTITION"
echo "✅ Device $PARTITION mounted to $MOUNT_DIR/$PARTITION"
else
echo "❌ USB-device not found"
fi
❯ Checking Remaining Free Space
This script is extremely simple; its task is to parse the remaining free space and alert if it's less than 90%. This script can be set up as a background daemon or integrated into your WM, for example.
#!/usr/bin/env bash
THRESHOLD=90
LOG_FILE="$HOME/.disk_usage.log"
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -ge "$THRESHOLD" ]; then
MESSAGE="⚠️ Disk space is used by $DISK_USAGE%!"
echo "$MESSAGE" | tee -a "$LOG_FILE"
notify-send "Disk Alert" "$MESSAGE"
fi
❯ CPU Usage Check
A script absolutely analogous to the previous one, except instead of disk space, it monitors CPU load.
#!/usr/bin/env bash
THRESHOLD=80
LOG_FILE="$HOME/.cpu_usage.log"
CPU_LOAD=$(awk '{print $1}' < /proc/loadavg | awk '{print $1*100}')
if (( ${CPU_LOAD%.*} >= THRESHOLD )); then
MESSAGE="⚠️ High CPU Usage: $CPU_LOAD%"
echo "$MESSAGE" | tee -a "$LOG_FILE"
notify-send "CPU Alert" "$MESSAGE"
fi
❯ Detecting Changes in Connected USB Devices
This script, on the first run, saves the current USB devices to a log file, then rechecks and compares the current connections with those from the file. Such a script can also be set up as a daemon.
#!/usr/bin/env bash
LOG_FILE="/var/log/usb_changes.log"
STATE_FILE="/var/log/usb_changes/usb_state.txt"
mkdir -p /var/log/usb_changes
echo "🔍 Searching installed USB... $(date)" | tee -a "$LOG_FILE"
lsusb > /var/log/current_usb.txt
if [ ! -f "$STATE_FILE" ]; then
cp /var/log/current_usb.txt "$STATE_FILE"
echo "📦 First save for USB" | tee -a "$LOG_FILE"
exit 0
fi
if ! diff "$STATE_FILE" /var/log/current_usb.txt >/dev/null; then
echo "⚠️ USB Connections changed" | tee -a "$LOG_FILE"
echo "--- After:" | tee -a "$LOG_FILE"
cat "$STATE_FILE" | tee -a "$LOG_FILE"
echo "--- Before:" | tee -a "$LOG_FILE"
cat /var/log/current_usb.txt | tee -a "$LOG_FILE"
cp /var/log/current_usb.txt "$STATE_FILE"
else
echo "✅ USB Connections not changed" | tee -a "$LOG_FILE"
fi
rm /var/log/current_usb.txt
❯ Memory Usage Analysis
I use this script for a brief memory summary; it gathers output from the free -h command, information from /proc/meminfo, a process list sorted by RSS memory usage, processes with heavy dirty page usage, and memory pressure.
Resident set size (RSS) — a term that, in the context of memory management in an operating system, means the size of memory pages allocated to a process and currently residing in RAM.
Memory pressure — is a term used to describe the state of a computer system when its available memory resources are heavily utilized.
#!/usr/bin/env bash
echo "=== Memory Analysis and OOM Killer Candidate Processes ==="
echo "Timestamp: $(date)"
echo ""
echo "1. Memory Summary:"
echo "-------------------"
free -h
echo ""
echo "2. Detailed RAM and Swap Usage:"
echo "----------------------------------------"
cat /proc/meminfo | grep -E "(MemTotal|MemAvailable|SwapTotal|SwapFree|SwapCached)"
echo ""
echo "3. Top 10 Processes by Resident Memory (RSS) Usage:"
echo "-------------------------------------------------------------"
ps aux --sort=-%mem | awk 'NR<=11 {printf "%-8s %-6s %-4s %-8s %-8s %s\n", $2, $1, $4, $3, $6/1024" MB", $11}'
echo ""
echo "4. Processes with Large Amounts of Dirty Memory:"
echo "------------------------------------------------------------------"
for pid in $(ps -eo pid --no-headers); do
if [ -f /proc/$pid/statm ]; then
dirty_pages=$(grep -i "Private_Dirty:" /proc/$pid/smaps 2>/dev/null | awk '{sum += $2} END {print sum}')
if [ -n "$dirty_pages" ] && [ "$dirty_pages" -gt 1000 ]; then
proc_name=$(cat /proc/$pid/comm 2>/dev/null)
dirty_kb=$((dirty_pages * 4))
echo "PID: $pid, Name: $proc_name, Dirty Memory: $dirty_kb KB"
fi
fi
done | sort -k6 -nr | head -10
echo ""
echo "5. Memory Pressure (PSI):"
echo "---------------------------"
if [ -f /proc/pressure/memory ]; then
cat /proc/pressure/memory
else
echo "Memory pressure information is not supported in this kernel version."
fi
echo ""
If you want to learn more about memory management in Linux, I wrote an article on the topic, where I broke everything down in detail.
❯ Displaying CPU and NVIDIA GPU Temperature
This script uses sensors and nvidia-smi to output temperature information for your CPU and GPU (NVIDIA):
#!/usr/bin/env bash
echo -e "\033[1;36m=== Temperatures ===\033[0m"
# CPU
cpu_temp=$(sensors | grep -E "Core [0-9]:" | awk '{print $3}' | sed 's/+//;s/°C//' | sort -nr | head -n1)
echo -e "🔥 \033[1;32mCPU: \033[1;33m${cpu_temp}°C\033[0m"
# GPU (NVIDIA)
if command -v nvidia-smi &> /dev/null; then
gpu_temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader 2>/dev/null)
if [ -n "$gpu_temp" ]; then
echo -e "🎮 \033[1;32mGPU: \033[1;33m${gpu_temp}°C\033[0m"
fi
fi
❯ Auto-formatting C/C++ Code
I use this Python script in my C/C++ projects; it is a wrapper for clang-format. It is convenient for me because it automates recursive formatting and styling, and you can add other formatters and run them all together through this script.
import argparse
import os
import subprocess
count = 0
def find_source_files(root_dir, ignore_dirs):
source_files = []
for dirpath, dirnames, filenames in os.walk(root_dir):
dirnames[:] = [d for d in dirnames if d not in ignore_dirs]
for filename in filenames:
if filename.endswith((".c", ".cpp", ".h", ".hpp", ".cc", ".cxx", ".hh")):
source_files.append(os.path.join(dirpath, filename))
return source_files
def format_files(files, clang_format, style):
global count
for file in files:
try:
cmd = [clang_format, "-i", "--style", style, file]
subprocess.run(cmd, check=True)
print(f"\033[32mFormatted:\033[0m {file}")
count += 1
except subprocess.CalledProcessError as e:
print(f"\033[31mError formatting {file}:\033[0m {e}")
def main():
parser = argparse.ArgumentParser(
description="Recursively format C/C++ files with clang-format"
)
parser.add_argument("root_dir", help="Root directory to search for source files")
parser.add_argument("--ignore", nargs="+", default=[], help="Directories to ignore")
parser.add_argument(
"--clang-format", default="clang-format", help="Path to clang-format executable"
)
parser.add_argument(
"--style", default="file", help="Formatting style (file/Google/LLVM/etc.)"
)
args = parser.parse_args()
print("\033[36m=== C/C++ Source Formatter ===\033[0m")
print(f"\033[33mRoot directory:\033[0m {args.root_dir}")
print(f"\033[33mIgnored directories:\033[0m {args.ignore or 'None'}")
print(f"\033[33mStyle:\033[0m {args.style}")
print("\033[36m" + "=" * 30 + "\033[0m")
source_files = find_source_files(args.root_dir, args.ignore)
if not source_files:
print("\033[33mNo C/C++ files found to format.\033[0m")
return
print(f"\033[33mFound {len(source_files)} files to format:\033[0m")
format_files(source_files, args.clang_format, args.style)
print(f"\033[32mFormatting complete ({count} files)!\033[0m")
if __name__ == "__main__":
main()
❯ SSL Certificate Check
This script allows checking how many days remain until the SSL certificate expiration date.
#!/usr/bin/env python3
import socket
import sys
import ssl
from datetime import datetime, timezone
def check_ssl_expiry(domain, days_before=7):
context = ssl.create_default_context()
with socket.create_connection((domain, 443)) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
expiry_date = datetime.strptime(cert["notAfter"], "%b %d %H:%M:%S %Y %Z")
remaining_days = (expiry_date - datetime.now(timezone.utc).replace(tzinfo=None)).days
print(f'Domain: {domain}')
print(f"Remaining days: {remaining_days}")
print(f'Days before: {days_before}')
check_ssl_expiry(sys.argv[1])
❯ Universal Unarchiver
This script is useful if you need a single command to extract archive contents, automatically selecting the command based on the extension.
#!/usr/bin/env bash
# extract.sh [archive file] [optional: output directory]
main() {
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
echo "Usage: extract.sh [archive file] [optional: output directory]"
exit 1
fi
file="$1"
output_dir="${2:-.}"
if ! [ -f "$file" ]; then
echo "File $file does not exist."
exit 1
fi
if ! [ -d "$output_dir" ]; then
mkdir -p "$output_dir" || { echo "Failed to create output directory $output_dir"; exit 1; }
echo "Created output directory $output_dir"
fi
extract_file "$file" "$output_dir"
}
extract_file() {
local file=$1
local output_dir=$2
case "$file" in
*.tar.xz) command_exists "tar" && tar -xvf "$file" -C "$output_dir" ;;
*.tar.gz) command_exists "tar" && tar -xzf "$file" -C "$output_dir" ;;
*.tar.bz2) command_exists "tar" && tar -xjf "$file" -C "$output_dir" ;;
*.tar) command_exists "tar" && tar -xf "$file" -C "$output_dir" ;;
*.tgz) command_exists "tar" && tar -xzf "$file" -C "$output_dir" ;;
*.bz|*.bz2) command_exists "bzip2" && bzip2 -d -k "$file" ;;
*.gz) command_exists "gunzip" && gunzip "$file" -c > "$output_dir" ;;
*.zip|*.jar) command_exists "unzip" && unzip "$file" -d "$output_dir" ;;
*.Z) command_exists "zcat" && zcat "$file" | tar -xvf - -C "$output_dir" ;;
*.rar) command_exists "rar" && rar x "$file" "$output_dir" ;;
*.7z) command_exists "7z" && 7z x "$file" -o"$output_dir" ;;
*) echo "Unsupported archive format." ;;
esac
}
command_exists() {
command -v "$1" >/dev/null 2>&1 || { echo >&2 "I require $1 but it's not installed. Aborting."; exit 1; }
}
main "$@"
In addition to this, I found an interesting comment from this article.

❯ Conclusion
Before using scripts with sudo or from unknown sources, always verify their contents. Do not run scripts as root without understanding what they do.
Thank you for reading the article! I hope you learned something new, or perhaps some alias or script sparked other ideas for you. If you found a nuance in the article itself — write in the comments.
If you liked the presented material, I can suggest you subscribe to my Telegram blog. Provided, of course, you enjoyed the article and want to see a bit more.
And you can view the scripts themselves in my repository. There you can find even more scripts in various programming languages, and also share your own developments via a PR.