Shell Scripting & Automation
Write reliable POSIX shell scripts — variables, conditionals, loops, functions, exit codes, and the quoting rules that keep automation from breaking in production.
Learning Objectives
- → Write a shell script with a proper shebang and understand how the OS uses it
- → Use variables, positional parameters ($1, $@, $#), and command substitution safely
- → Implement conditionals (if/case) and loops (for/while) in shell scripts
- → Explain exit codes and use them for error handling in automation
- → Apply quoting rules to avoid word-splitting and globbing bugs
Why Script Instead of Typing Commands
A script turns a fragile sequence of manual steps into something repeatable, reviewable, and safe to run at 3am by someone who isn't you. Every production automation pipeline — CI/CD, cron jobs, deployment tooling — is built on the same shell-scripting fundamentals.
Anatomy of a Script
#!/usr/bin/env bash
set -euo pipefail
echo "Backing up $1..."
- The shebang (
#!/usr/bin/env bash) tells the kernel which interpreter runs the rest of the file. Usingenv bashinstead of a hardcoded/bin/bashpath is more portable across systems where bash lives in a different location. set -e— exit immediately if any command fails, instead of silently continuingset -u— treat any unset variable as an error, catching typos before they cause damageset -o pipefail— a pipeline's exit code reflects the first failing command, not just the last one
Variables and Quoting
name="alice" # no spaces around =
echo "$name" # always quote expansions
Unquoted variables are word-split and glob-expanded by the shell. A variable holding my file.txt becomes two separate arguments (my and file.txt) if left unquoted — a classic source of scripts that "work on my machine" and break on real data.
Positional parameters: $1, $2, ... are the script's arguments; $@ is all of them; $# is the count; $0 is the script's own name.
Conditionals
if [ -d "$SRC" ]; then
echo "Directory exists"
else
echo "Missing: $SRC" >&2
exit 1
fi
Common test operators: -f (regular file exists), -d (directory exists), -z (string is empty), -eq/-ne (numeric equality).
A case statement branches cleanly on multiple string patterns without a long if/elif chain:
case "$env" in
prod) echo "careful!";;
staging|dev) echo "safe to experiment";;
*) echo "unknown environment"; exit 1;;
esac
Loops
for env in dev staging prod; do
echo "Deploying to $env"
done
while read -r line; do
echo "Processing: $line"
done < input.txt
while read -r line; do ... done < file is the safe way to process a file line-by-line — it doesn't word-split or glob-expand each line, unlike for line in $(cat file).
Functions
backup_dir() {
local target="$1"
tar -czf "${target}.tar.gz" "$target"
}
local scopes a variable to the function — without it, every variable is global and can silently clobber a caller's state.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 126 | Command found but not executable |
| 127 | Command not found |
| 130 | Terminated by Ctrl+C (SIGINT) |
Exit codes are how scripts communicate success/failure to whatever calls them — if my_script.sh; then ... branches on exactly this.
Common Pitfalls
- Unquoted variables causing word-splitting (
rm $DIR/*with an unset or empty$DIRcan expand dangerously) - Assuming
==works the same in every shell — it's a bash-ism, POSIXshonly guarantees= set -edoesn't always do what people expect inside conditionals or the middle of a pipeline — test your assumptions- Forgetting execute permission (
chmod +x script.sh) before trying to run a script directly
The very first line of a script isn't a comment to humans — it's an instruction to the kernel about which program should execute the rest of the file.
What is the purpose of the shebang line at the top of a script?
Different exit codes carry different, widely-agreed meanings that automation tooling relies on.
What exit code conventionally means 'command not found'?
The shell splits unquoted variable expansions on whitespace and expands glob characters like * before your script ever sees the value.
Why should you write "$file" instead of $file when the variable might contain a space?
💪 Exercises & Challenges
Shell Scripting & Automation MCQ
Test your understanding of Shell Scripting & Automation.
Harden a Backup Script
You're given a script skeleton that is missing quoting and error handling. Rewrite it, fixing: (1) add a proper shebang, (2) quote every variable expansion, (3) add `set -euo pipefail` right after the
Diagnose the Broken Deploy Script
A junior engineer's deploy script keeps silently continuing even after a failed step, and once corrupted a directory literally named `my backup` because of unquoted variable expansion splitting it int