Bash scripting guide
32 short parts, in the order you need them. Each example was run with bash 5.2.37 (and dash, where portability is the point), and the output shown is what it printed.
- 01The shebang lineWhat the kernel does with #!, why #!/usr/bin/env bash and #!/bin/bash both exist, and the ways a shebang line breaks.
- 02Running scriptsThe four ways to start a script (./script, bash script, PATH, source), what each one changes, and the errors you get when one goes wrong.
- 03VariablesAssigning and reading shell variables, the no-spaces rule, braces, unset vs empty, scope, readonly, and the special variables bash sets for you.
- 04Environment variablesHow export passes variables to child processes, the one-command NAME=value prefix, loading .env files, and why a child cannot change its parent.
- 05QuotingSingle quotes, double quotes, backslashes and $'...', what each protects, and the unquoted-variable bugs they prevent, each shown failing and then fixed.
- 06Word splittingWhen bash splits expansion results into separate words, how IFS controls it, and why for line in $(cat file) does not loop over lines.
- 07Parameter expansionThe ${...} operators for defaults, lengths, substrings, trimming prefixes and suffixes, search and replace, and case conversion, without calling sed or cut.
- 08Command substitutionCapturing a command's output with $(...), what happens to trailing newlines and stderr, how to check the exit status, and the local trap that hides failures.
- 09ArithmeticInteger math with $(( )) and (( )), the exit status of (( )) that breaks set -e, leading-zero octal surprises, and what to use for decimals.
- 10ArraysIndexed arrays in bash, creating, reading, appending, looping, slicing and removing elements, and using them to build command lines safely.
- 11Associative arraysBash's string-keyed maps, declare -A, testing whether a key exists, counting things, loading a config file, and the unordered-keys and missing-declare traps.
- 12ConditionalsHow if, elif, &&, || and ! decide using exit statuses, the three test syntaxes, guard clauses, and why a && b || c is not an if-else.
- 13Test operatorsEvery file, string and number test for [ ] and [[ ]], pattern and regex matching, and the traps like [ $a > $b ] creating a file.
- 14The case statementMatching one value against glob patterns with case, alternatives with |, the default branch, fall-through with ;& and ;;&, and parsing options with case.
- 15Loopsfor over lists, files and ranges, C-style for, while and until, break and continue, retry loops, and redirecting a whole loop's input or output.
- 16Reading files line by lineThe correct while IFS= read -r line loop part by part, the missing last line, the pipe-subshell trap, CSV fields, mapfile and stdin-stealing commands.
- 17FunctionsDefining and calling bash functions, arguments, local variables, return status versus output, namerefs, and sourcing a function library.
- 18Exit codesWhat exit statuses mean, how $? works, the reserved values 126, 127 and 128+N, PIPESTATUS, and how to choose codes for your own scripts.
- 19Strict mode and its caveatsWhat set -euo pipefail actually does, the cases where -e silently does nothing, the traps in -u and pipefail, and a balanced way to use it.
- 20Traps and signalsRunning cleanup code with trap on EXIT, handling INT and TERM, the ERR pseudo-signal, and the timing and scoping rules that trip people up.
- 21RedirectionHow >, >>, 2>, 2>&1, &>, < and exec move a command's input and output between files and file descriptors, and why the order matters.
- 22Here-documents and here-stringsFeed multi-line text to a command with <
- 23Pipes and pipelinesHow cmd1 | cmd2 connects processes, which exit status a pipeline returns, PIPESTATUS, pipefail, SIGPIPE, and why variables set in a piped loop vanish.
- 24Process substitutionUse <(cmd) and >(cmd) to hand a command's output to a program that wants a file name, keep while-read loops in the current shell, and avoid its timing traps.
- 25Subshells and command groupingThe difference between ( ... ) and { ...; }, what a subshell inherits and what it cannot change, which constructs create one, and what that costs.
- 26Script argumentsPositional parameters $1 to ${10}, $# and $0, why "$@" is almost always right and "$*" rarely, shift, getopts, and ending options with --.
- 27Brace expansionGenerate lists of words with {a,b,c} and sequences with {1..10} and {01..10..2}, why {1..$n} does not work, and how braces differ from globs.
- 28GlobbingHow *, ? and [...] match file names, what happens when nothing matches, and the shell options nullglob, failglob, dotglob, globstar and extglob.
- 29String manipulationLength, substrings, prefix and suffix removal, search and replace, case, trimming, splitting and joining, done with bash's own expansions instead of external tools.
- 30Debugging bash scriptsCheck syntax with bash -n, trace with set -x, add file and line numbers through PS4, send the trace elsewhere with BASH_XTRACEFD, and report failures with trap ERR.
- 31Bash idioms for real scriptsThe small patterns that make scripts robust - die(), logging to stderr, ${1:?usage}, command -v checks, mktemp with trap cleanup, retries with backoff, locking and safe config parsing.
- 32POSIX sh vs bashThe bashisms that break when a script runs under dash or another POSIX sh, the exact errors dash prints, and the portable replacement for each.