Bash style guide
Style Guide
Based on Community Bash Style Guide
When to use bash
- ✔️ It need to glue userland utilities together.
- ❌ Do complex tasks (e.g. database queries).
Style conventions
Use the
#!/usr/bin/env bash
shebang wherever possible.Memorize and utilize
set -eu -o pipefail
at the very beginning of your code.- Never write a script without
set -e
at the very very beginning.- This instructs bash to terminate in case a command or chain of command finishes with a non-zero exit status, avoiding unhandled error conditions.
- Use constructs like
if myprogramm --parameter ; then ...
for calls that might fail and require specific error handling. Use a cleanup trap for everything else.
- Use
set -u
in your scripts.- This will terminate your scripts in case an uninitialized variable is accessed.
- Uninitialized variables will fail in case it’s used in another script which sets the
-u
flag, better for security.
- Use
set -o pipefail
to get an exit status from a pipeline (last non-zero will be returned).
- Never write a script without
Never use TAB for indentation.
- Consistently use two (2) or four (4) character indentation.
Always put parameters in double-quotes:
util "--argument" "${variable}"
.Avoid putting
if .. then
,while .. do
,for .. do
,case .. in
on a new line.1
2
3
4
5
6
7
8
9
10
11if ${event}; then
...
fi
while ${event}; do
...
done
for v in ${list[@]}; do
...
doneNever forget that you cannot put a space/blank between a variable name and it’s value during an assignment
1
2RET1=false # assign
RET2 = false # will not assignAlways set local function variables
local
.Write clear code.
- Never obfuscate what the script is trying to do.
- Never shorten uncessesarily with a lot of commands per line of code chained with a semicolon.
Bash does not have a concept of public and private functions.
- Public functions get generic names, whereas.
- Private functions are prepended by two underscores (RedHatconvention).
Try to stick to the
pushd
,popd
, anddirs
builtins for directory stack manipulation where sensible.Every line must have a maximum of eighty (80) terminal columns
Like in other dynamic languages, switch/case blocks should be aligned:
1
2
3
4
5case ${contenders}; in
teller) x=4 ;;
ulam) c=1 ;;
neumann) v=7 ;;
esacOnly
trap
/ handle signals you actually do care about.Use the builtin
readonly
when declaring constants and immutable variable.Assign integer variables, arrays, etc. with
typeset
/declare
(see also).Always work with return values instead of strings passed from a function or userland utility (where applicable).
Write generic small check functions instead of large init and clean-up code.
1
2
3
4
5
6
7# both functions return non-zero on error
function is_valid_string?() {
[[ $@ =~ ^[A-Za-z0-9]*$ ]]
}
function is_integer?() {
[[ $@ =~ ^-?[0-9]+$ ]]
}Be as modular and plugable as possible. If a project gets bigger, split it up into smaller files with clear and obvious naming scheme.
Clearly document code parts that are not easily understood (long chains of piped commands for example).
Try to stick to restricted mode where sensible and possible to use.
- Use
set -r
with caution: while this flag is very useful for security sensitive environments, scripts have to be written with the flag in mind. - Adding restricted mode to an existing script will most likely break it.
- Use
Scripts should somewhat reflect the following general layout:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# AUTHORS, LICENSE and DOCUMENTATION
#
set -eu -o pipefail
Readonly Variables
Global Variables
Import ("source scriptname") of external source code
Functions
`-. function local variables
`-. clearly describe interfaces: return either a code or string
Main
`-. option parsing
`-. log file and syslog handling
`-. temp. file and named pipe handling
`-. signal traps
------------------------------------------------------------------------
To keep in mind:
- quoting of all variables passed when executing sub-shells or cli tools
- testing of functions, conditionals and flow (see style guide)
- makes restricted mode ("set -r") for security sense here?Silence is golden - like in any UNIX programm, avoid cluttering the terminal with useless output.