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
| Concept | Example | Notes |
|---|---|---|
| Variables | NAME="Alice" | No spaces around = |
| Command substitution | NOW=$(date) | Use $(), not backticks |
| Conditionals | if [[ -f "$file" ]] | Use [[ ]] not [ ] |
| Loops | for i in {1..5}; do ... done | Works for ranges, arrays, globs |
| Functions | my_func() { echo "hi"; } | Call with just my_func |
| Exit codes | exit 0 (success) / exit 1 (error) | Check with $? |
Good Habits for Reliable Scripts
- Always quote variables:
"$variable"— prevents word splitting and glob expansion. - Use
set -euo pipefailat the top of every script. - Print meaningful error messages to
stderrusing>&2. - Test your scripts with
bash -n script.sh(syntax check) before running. - 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.