Why Learn Bash Scripting?

Bash is the default shell on most Linux systems, and scripting with it is one of the most practical skills a Linux user can develop. Unlike full programming languages, Bash scripts shine at automating repetitive tasks, gluing together command-line tools, and managing files and processes. You don't need to be a software developer to benefit from it.

This article focuses on real, immediately useful examples rather than dry syntax lessons.

The Anatomy of a Bash Script

Every Bash script should start with a shebang line and use the set builtin for safer execution:

#!/usr/bin/env bash
set -euo pipefail

# -e: exit on any error
# -u: treat unset variables as errors
# -o pipefail: catch errors in pipelines

Make your script executable: chmod +x myscript.sh

Example 1: Automated Backup Script

This script backs up a directory to a timestamped archive:

#!/usr/bin/env bash
set -euo pipefail

SOURCE_DIR="$HOME/Documents"
BACKUP_DIR="$HOME/Backups"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
ARCHIVE_NAME="documents_backup_${TIMESTAMP}.tar.gz"

mkdir -p "$BACKUP_DIR"
tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" "$SOURCE_DIR"
echo "Backup created: ${BACKUP_DIR}/${ARCHIVE_NAME}"

Schedule it with cron (crontab -e) to run nightly at 2am: 0 2 * * * /path/to/backup.sh

Example 2: Batch Rename Files

Rename all .jpeg files in a directory to .jpg:

#!/usr/bin/env bash
set -euo pipefail

for file in *.jpeg; do
  [ -f "$file" ] || continue
  mv "$file" "${file%.jpeg}.jpg"
  echo "Renamed: $file -> ${file%.jpeg}.jpg"
done

The ${file%.jpeg} syntax strips the .jpeg suffix — no need for sed or awk.

Example 3: Check if a Service is Running

A simple monitoring script that sends an alert if a service is down:

#!/usr/bin/env bash
set -euo pipefail

SERVICE="nginx"

if systemctl is-active --quiet "$SERVICE"; then
  echo "$SERVICE is running."
else
  echo "WARNING: $SERVICE is NOT running!" >&2
  # Optionally restart it:
  # sudo systemctl restart "$SERVICE"
fi

Example 4: Process a List of Files with Error Handling

Loop over a list of files, skipping ones that don't exist:

#!/usr/bin/env bash
set -euo pipefail

FILES=("config.yml" "README.md" "notes.txt")

for f in "${FILES[@]}"; do
  if [[ -f "$f" ]]; then
    echo "Processing: $f ($(wc -l < "$f") lines)"
  else
    echo "Skipping: $f (not found)" >&2
  fi
done

Key Bash Concepts to Know

ConceptExampleNotes
VariablesNAME="Alice"No spaces around =
Command substitutionNOW=$(date)Use $(), not backticks
Conditionalsif [[ -f "$file" ]]Use [[ ]] not [ ]
Loopsfor i in {1..5}; do ... doneWorks for ranges, arrays, globs
Functionsmy_func() { echo "hi"; }Call with just my_func
Exit codesexit 0 (success) / exit 1 (error)Check with $?

Good Habits for Reliable Scripts

  1. Always quote variables: "$variable" — prevents word splitting and glob expansion.
  2. Use set -euo pipefail at the top of every script.
  3. Print meaningful error messages to stderr using >&2.
  4. Test your scripts with bash -n script.sh (syntax check) before running.
  5. Use shellcheck (sudo apt install shellcheck) — it catches common bugs automatically.

Bash scripting is a skill that compounds. Every script you write teaches you something new, and the time savings add up quickly. Start small, automate something annoying, and go from there.