Linux Learning · Part 4 of 7

🐚 Shell Scripting

Bash variables · loops · conditionals · functions · real-world automation scripts.


Script Basics

Script structure and execution
#!/usr/bin/env bash       # shebang — tells OS to use bash
set -euo pipefail         # -e=exit on error, -u=error on undef vars, pipefail

echo "Hello, $(whoami)!"
echo "Running on: $(hostname)"
echo "Date: $(date +%Y-%m-%d)"

# Make executable and run:
$ chmod +x myscript.sh
$ ./myscript.sh

# Debug mode — prints every command before running:
$ bash -x myscript.sh

Variables

Variables and special vars
NAME="Saad"                          # no spaces around =
TODAY=$(date +%Y-%m-%d)              # command substitution
FILES=$(ls /etc/*.conf | wc -l)
readonly MAX_RETRIES=3               # constant

# Special variables:
echo "Script: $0  |  Args: $@  |  Count: $#  |  PID: $$  |  Last exit: $?"

# Default values:
ENV=${1:-"production"}               # use "production" if $1 not set
LOG=${LOG_FILE:-"/var/log/app.log"}

Conditionals

if / elif / else and test operators
if [[ $AGE -ge 18 ]]; then
  echo "Adult"
elif [[ $AGE -ge 13 ]]; then
  echo "Teenager"
else
  echo "Child"
fi

# Numeric: -eq -ne -lt -le -gt -ge
# String:  == != -z (empty) -n (not empty)
# Files:   -f (file) -d (dir) -e (exists) -r -w -x

if [[ -f "/etc/nginx/nginx.conf" ]]; then echo "nginx installed"; fi

# One-liners:
[[ -d /tmp/work ]] || mkdir -p /tmp/work
ping -c1 google.com &>/dev/null && echo "Online" || echo "Offline"

# case statement:
case "$OS" in
  ubuntu|debian)  PKG="apt"  ;;
  rhel|centos)    PKG="dnf"  ;;
  *)              echo "Unknown"; exit 1 ;;
esac

Loops

for, while, until loops
# for — iterate over list
for pkg in nginx git curl htop; do
  sudo apt install -y "$pkg"
done

# for — range
for i in {1..10}; do echo "Item $i"; done

# for — files
for file in /etc/*.conf; do echo "Config: $file"; done

# while loop
COUNT=0
while [[ $COUNT -lt 5 ]]; do
  echo "Count: $COUNT"
  ((COUNT++))
done

# Read file line by line
while IFS= read -r line; do
  echo "Processing: $line"
done < /etc/hosts

# until loop — wait for something
until ping -c1 server &>/dev/null; do
  echo "Waiting..."; sleep 5
done
echo "Server is up!"

Functions

Defining and calling functions
log() {
  local level="$1"
  local message="$2"
  echo "[$(date +%H:%M:%S)] [$level] $message"
}
log "INFO"  "Script started"
log "ERROR" "Something went wrong"

# Return true/false (exit code):
is_root() { [[ $EUID -eq 0 ]]; }

if is_root; then echo "Running as root"
else echo "Not root — use sudo"; exit 1; fi

# Return a value via echo:
get_os() {
  if   [[ -f /etc/debian_version ]]; then echo "debian"
  elif [[ -f /etc/redhat-release ]];  then echo "rhel"
  else echo "unknown"; fi
}
OS=$(get_os)
echo "Detected: $OS"

Real-World Script Examples

Automated backup script
#!/usr/bin/env bash
set -euo pipefail

BACKUP_SRC="/var/www/html"
BACKUP_DEST="/backups"
DATE=$(date +%Y-%m-%d_%H-%M)
ARCHIVE="$BACKUP_DEST/web-$DATE.tar.gz"
KEEP_DAYS=7

mkdir -p "$BACKUP_DEST"
tar -czf "$ARCHIVE" "$BACKUP_SRC"
echo "Backup: $ARCHIVE ($(du -sh "$ARCHIVE" | cut -f1))"

# Remove backups older than $KEEP_DAYS days:
find "$BACKUP_DEST" -name "web-*.tar.gz" -mtime +$KEEP_DAYS -delete
echo "Old backups cleaned."
System health check
#!/usr/bin/env bash
WARN_CPU=80; WARN_DISK=90; WARN_MEM=85

CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print int($2)}')
DISK=$(df / | awk 'NR==2 {print int($5)}')
MEM=$(free | awk '/Mem/ {printf "%.0f", $3/$2*100}')

echo "=== System Health ==="
echo "CPU:  $CPU%  $([ $CPU  -gt $WARN_CPU  ] && echo '⚠ HIGH' || echo '✓ OK')"
echo "Disk: $DISK% $([ $DISK -gt $WARN_DISK ] && echo '⚠ HIGH' || echo '✓ OK')"
echo "Mem:  $MEM%  $([ $MEM  -gt $WARN_MEM  ] && echo '⚠ HIGH' || echo '✓ OK')"
Error handling with trap
#!/usr/bin/env bash
set -euo pipefail

cleanup() {
  echo "Cleaning up temp files..."
  rm -f /tmp/myscript_*
}
trap 'echo "Error on line $LINENO"; exit 1' ERR
trap 'cleanup' EXIT

# Script logic here — cleanup runs automatically on exit
🖥
Sponsored

Need a Linux VPS? Try DigitalOcean

Spin up a droplet and run these scripts on a real server in 60 seconds.

Get Started →