/user/kayd @ devops :~$ ls ~/series/bash-for-production/

series · 10 articles · 24k words

Bash for Production

Ten articles on writing bash that survives being run unattended: why set -e is not error handling, string operations without forking, retries and self-repair, and when to stop using bash.

Bash is the language your infrastructure is already written in. Not by choice exactly — it accumulated. The deploy script, the cron job, the entrypoint in the Dockerfile, the twelve lines in the CI config. That code runs unattended, often as root, usually with no tests, and it is the least reviewed code you own.

These ten articles are about making that code not break at three in the morning.

set -e is not error handling

If there is one thing to take from this hub it is this, because almost everyone who writes shell believes otherwise.

set -euo pipefail at the top of a script is a good default and it is not a safety net. It does not fire when a command fails inside a condition. It does not fire for a function called in an if. Without pipefail it does not fire when the first command in a pipeline fails and the last one succeeds — which is exactly the shape of generate_the_data | tee output.txt, where the data generator dies, tee cheerfully writes an empty file, and the script continues with a zero exit code.

The foundational article walks into that bug deliberately at step 4, and the error handling article is the full treatment: exit codes, trap, signals, and checking things before you use them rather than after.

The four habits that separate a script from a program

Quote everything. Unquoted $var is the most common bug in shell, and it shows up the day a filename contains a space. rm -rf $DIR/ with an empty DIR is the version of this bug that ends careers. Quote it; use "${DIR:?}" when empty is not acceptable.

Assume it will run twice. A retried CI job, a cron that overlaps itself, an engineer running the script by hand to see what it does. Appending a line to a config is not safe to repeat. Creating a directory with mkdir -p is. Design for the second run and you have removed a class of incident.

Fail loudly, in one place. A script that prints error and exits 1 is useless in a log with four thousand lines in it. Say what failed, what it was trying to do, and what the caller should do next. This is what the “make failures clear” step is about, and it costs a helper function.

Retry the things that are worth retrying, and only those. A network call, yes. A command that failed because a file does not exist, no — retrying that just takes longer to fail. The self-healing article is about that distinction: detect, diagnose, repair the environment if you can, and give up cleanly if you cannot.

Forking is what makes shell slow

The four string articles look like a reference and they teach one idea. Bash can do a surprising amount of string work with its own parameter expansion, and every time it does, you avoid starting a process.

${path##*/} is basename. ${file%.*} strips an extension. ${var,,} is tr A-Z a-z. Each of these is a syntax lookup instead of a fork, an exec, a pipe, and a wait. In a loop over ten files that is invisible. In a loop over ten thousand log lines it is the difference between two seconds and two minutes — the filename article benchmarks basename against parameter expansion against awk instead of asserting it.

That article is also the best example in the series of the failure-first format: it starts with basename, breaks on a symlinked deploy directory, breaks again on a filename with a space, and fixes each one as it appears.

When to stop using bash

Bash is the right tool for gluing programs together, and a poor one for anything with structure. Reach for Python or Go when:

  • you need a data structure that is not a flat list of strings;
  • you are parsing anything nested — JSON, YAML, XML;
  • you need to handle errors differently depending on what went wrong;
  • the script has passed roughly three hundred lines, or two people have said “I am not sure what this does”.

The code shortening article is explicit about the other half of this: shorter is not automatically better, and it has a section on when not to compress. Shell that only its author can read is worse than the long version, because the person debugging it at 3am is not going to be its author.

How to read this

Start with Mastering Bash — it is the one that goes end to end and it will tell you which of the others you need.

If you already write shell professionally, the two with the most in them for you are error handling and automation patterns, which covers retries, parallel execution across servers, and templating — the things a nightly deploy script needs and usually does not have.

The string articles are worth skimming once so you know what is in them, then keeping to hand. The first is a short overview; the other three are the detail.

What you need

Bash 4 or newer and a terminal. macOS ships bash 3.2 for licensing reasons, so a few of the newer expansions want brew install bash — the articles say so where it matters.

All 10 articles

Start here

One article that goes from a two-line echo script to a deployment script, hitting the classic traps in order rather than listing them.

  1. Mastering Bash: From echo to Production Deployment Script Master bash by solving real problems: start with a simple echo script, add variables, hit the set -e trap, debug with set -x, and build a deployment script. 9 min read · Aug 2023

Scripts that survive being unattended

The difference between a script you run and a script that runs on a schedule: it has to notice failure, react to it, and be safe to run again.

  1. Bash Error Handling: Patterns for Bulletproof Scripts Essential Bash error handling techniques that turn fragile scripts into reliable automation. Learn exit codes, signal traps, and defensive failure patterns. 12 min read · Aug 2023
  2. Self-Healing Bash: Functions That Recover From Failures Master self-healing Bash functions that detect, troubleshoot, and recover from failures automatically, with practical examples for resilient scripts. 20 min read · Aug 2023
  3. Advanced Bash Scripting for Automation Bash automation patterns for multi-server deployments: error handling, retries, parallel execution, and templating that make long-running scripts reliable. 17 min read · Aug 2023

Handling text without leaving the shell

Four articles on bash's own string operations. Read them for the pattern more than the functions: nearly every one replaces a subprocess with syntax, and subprocesses are what make shell scripts slow.

  1. Advanced Bash String Operations An overview of custom Bash string functions for log processing and everyday scripting, linking to focused guides on trimming, splitting, and validation. 2 min read · Feb 2023
  2. Bash String Functions: Trimming, Case, and Reversal Bash trim functions (ltrim, rtrim, trim) and string reversal for cleaning whitespace in CSV imports and log normalization, with performance comparisons. 5 min read · Feb 2023
  3. Bash String Functions: Search, Split, Count, Extract Bash functions for length checks, case conversion, substitution, counting, splitting, and extracting fields from CSV and log data, with edge-case handling. 8 min read · Feb 2023
  4. Bash String Validation, Generation & a Library Bash functions for random IDs, input sanitization, CSV parsing, password strength, slug generation, plus a complete production string library to source. 9 min read · Feb 2023

Shorter, and the cost of shorter

Concision is worth something in shell and it is worth less than people think. Both of these measure rather than assert.

  1. Bash Code Shortening: Writing Concise Shell Scripts Proven Bash code shortening techniques to simplify shell scripts while keeping them readable and fast, with practical examples and best practices. 26 min read · Aug 2023
  2. Filename Extraction: basename to a Production File Pipeline Learn filename extraction the hard way: start with basename, hit the spaces bug, fix it, then benchmark it against parameter expansion yourself. 11 min read · Apr 2024

Get new articles by email

One DevOps article a week, plus the 18-cheatsheet PDF pack. No spam, one click to leave.