Control and functions

Branch with if and case

Test command success with if and select a small set of named modes with case.

10 minute lesson

~~~

In shell, if doesn’t test truth the way other languages do. It runs a command and branches on its exit status: zero takes the then branch, anything else goes to else. case matches one value against patterns and is clear for command modes.

if runs commands

Because if evaluates a command’s exit status, any command works as a condition:

if grep -q 'server_name' /etc/nginx/nginx.conf; then
  printf '%s\n' 'config mentions server_name'
else
  printf '%s\n' 'no server_name found' >&2
fi

Tests on strings and files use [[ ... ]], which is itself a command that exits zero when the test holds:

if [[ -f /etc/nginx/nginx.conf && $USER == 'deploy' ]]; then
  printf '%s\n' 'ready to check the config'
fi

Prefer [[ ... ]] over the older [ ... ] for Bash-specific scripts: it doesn’t word-split unquoted variables and it supports pattern matching. I still quote arbitrary values in tests — the habit protects you in every other context where quoting does matter.

case for named modes

When a script accepts a small set of subcommands, a chain of elif branches gets noisy fast. Dispatch a mode:

case ${1:-} in
  check) printf '%s\n' 'checking' ;;
  run) printf '%s\n' 'running' ;;
  *) printf 'usage: %s {check|run}\n' "$0" >&2; exit 2 ;;
esac

${1:-} expands to an empty string when no argument was given, so the script behaves under set -u instead of dying with an unbound-variable error. Each branch ends with ;;.

The * pattern is the part people forget. It catches everything the named patterns missed. Leave it out and unknown input matches nothing — the case finishes silently and the script continues as if the argument were fine.

Verify every path

Run every accepted value and one rejected value:

./service-ctl check   # checking
./service-ctl run     # running
./service-ctl stop    # usage: ./service-ctl {check|run}

Each path should have a documented status. After the rejected call, echo $? must print 2 — callers and schedulers branch on that number, not on the usage text.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →