LESSON · 1 OF 5

Anatomy of a production-quality script

Anatomy of a production-quality script

Every script in this final topic follows the same shape. Learn it once, apply it forever.

The header

bash
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT_NAME="${0##*/}"
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  • Portable shebang.
  • Safe defaults from topic 11.
  • SCRIPT_NAME and SCRIPT_DIR so the script knows where it lives.

Helpers

bash
die() {
  echo "$SCRIPT_NAME: $*" >&2
  exit 1
}

log() {
  echo "[$(date +%H:%M:%S)] $*"
}

Two utility functions almost every script wants. die for fatal errors, log for timestamped normal output.

Argument parsing

Even for scripts with one argument, validate:

bash
[[ $# -eq 1 ]] || die "usage: $SCRIPT_NAME <target>"
target=$1

For flags, use getopts from topic 4.

Cleanup

If the script writes to /tmp or holds locks:

bash
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT

Main logic in a function

bash
main() {
  parse_args "$@"
  do_the_thing
  finish_up
}

main "$@"

Wrapping the top-level logic in main (and calling it at the end) makes the script easier to read and easier to test. Functions defined above main are visible when main runs.

What we're building

The next three nodes are complete production-quality scripts: a backup script, a health check, and a deploy script. Each one follows this shape and exercises multiple topics you've learned. Read the code, run it, and see how the pieces fit together.

Spin up a fresh environment and practice live.
linux-devops-basic · fresh machine · ready in under a minute