terminal:scripting:bash_recipes
This is an old revision of the document!
Table of Contents
Bash Recipes
Reference for writing scripts: macbook-qol.sh in this folder is a real
example of most of these patterns.
Skeleton
#!/usr/bin/env bash set -euo pipefail # die on error, unset vars, pipe failures IFS=$'\n\t' # optional: safer word splitting
Arguments and flags
for arg in "$@"; do case $arg in -v|--verbose) VERBOSE=1 ;; -o|--output) shift; OUT=$1 ;; *) echo "unknown: $arg" >&2; exit 1 ;; esac shift done
$0 script name · $1..$9 args · $@ all args · $# count · $$ PID ·
$? last exit code · $! last background PID
Env-var tunables with defaults (the pattern this repo's script uses):
TURBO="${TURBO:-off}" # ${VAR:-default} die "needs TURBO" # if unset: ${VAR:?message}
Conditionals
[[ -f file ]] [[ -d dir ]] [[ -z $str ]] [[ -n $str ]] [[ $a == $b ]] [[ $a == foo* ]] [[ $n -gt 3 ]] # < -eq -ne -lt -le -ge [[ $x =~ ^[0-9]+$ ]] # regex match command -v foo >/dev/null # command exists
Files: -e exists, -r/-w/-x readable/writable/executable, -s non-empty,
-nt/-ot newer/older.
Loops
for f in *.txt; do echo "$f"; done for i in {1..10}; do ...; done while IFS= read -r line; do ...; done < file find . -type f -print0 | while IFS= read -r -d '' f; do ...; done # safe
Functions / output / errors
die() { printf 'Error: %s\n' "$*" >&2; exit 1; } say() { printf '==> %s\n' "$*"; } trap 'echo "interrupted"; exit 130' INT trap cleanup EXIT # run on any exit
Return values: return 1 sets $?. Get output: result=“$(myfunc)”.
Strings
${s#prefix} ${s%suffix} # strip shortest ${s##*/} # basename ${s%/*} # dirname ${s/old/new} ${s//o/n} # replace first / all ${#s} # length ${s:2:5} # substring ${s^^} ${s,,} # upper / lower
Arrays
a=(one two three) echo "${a[1]}" "${a[@]}" "${#a[@]}" a+=(four) mapfile -t lines < file # file -> array
Heredocs
cat <<EOF # expands $vars template for $USER EOF cat <<'EOF' # literal, no expansion no $expansion here EOF
Debugging
bash -x script.sh # trace every command shellcheck script.sh # linter: catches real bugs set -x; ... ; set +x # trace a section
Gotchas
- [[ not
[:[is a command with worse semantics. - Quote everything:
“$var”: unquoted vars split on spaces. cdin a script doesn't affect your shell; use( cd dir && … )subshells.localonly exists inside functions.exitinside$(…)exits the subshell, not the script.pipefail+set -oat top orfoo | grep xreturns 0 even when foo fails.
Reading input
read -rp "Name? " name read -rsp "Password: " pw; echo # -s silent read -t 5 -n1 -p "continue? " || exit
Running as root
[[ $EUID -ne 0 ]] && exec sudo -E bash "$0" "$@" # re-exec via sudo
See Also
terminal/scripting/bash_recipes.1792792621.txt.gz · Last modified: by 127.0.0.1
