- Variables and substitution — Variables store values without type declarations:
bash
NAME="deploy"
DATE=$(date +%Y-%m-%d) # command substitution
LOGFILE="/var/log/${NAME}-${DATE}.log"
echo "Starting $NAME at $DATE" | tee "$LOGFILE"
Special variables: $0 (script name), $1-$9 (positional args), $# (arg count), $? (last exit code), $@ (all args).
- Conditionals with if/test — Bash uses
test(or[ ]/) for conditions:
bash
if -f "$CONFIG_FILE" ; then
source "$CONFIG_FILE"
elif -f "/etc/default/myapp" ; then
source "/etc/default/myapp"
else
echo "No config found, using defaults"
fi
Key test operators: -f (file exists), -d (directory exists), -z (string empty), -n (string not empty), -eq/-ne/-lt/-gt (numeric comparison).
- Loops for iteration — Three loop constructs:
bash
# for loop — iterate over list
for file in /var/log/.log; do
echo "Processing $file"
gzip "$file"
done
# while loop — condition-based
while read -r line; do
echo "Line: $line"
done < input.txt
# until loop — inverse while (rarely used)
until ping -c 1 server.local; do
sleep 5
done
- Functions for reuse — Group commands into named, reusable blocks:
bash
log() {
echo "[$(date '+%H:%M:%S')] $1" >> "$LOGFILE"
}
backup_dir() {
local src="$1"
local dest="$2"
tar -czf "$dest/$(basename $src)-$(date +%Y%m%d).tar.gz" "$src"
log "Backed up $src to $dest"
}
backup_dir "/etc" "/backups"
- Exit codes and error handling — Every command returns an exit code (0 = success, non-zero = failure). Robust scripts check these:
bash
set -euo pipefail # exit on error, undefined vars, pipe failures
trap 'echo "Error on line $LINENO"; exit 1' ERR
set -e stops execution on any error. set -u treats undefined variables as errors. set -o pipefail catches failures in piped commands.