alexeev-dev notes

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:

❯ Network Utilities

I have a whole set of scripts for network-related tasks:

❯ 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.

Sources