This project now has its own homepage at bash3boilerplate.sh.
I recently tweeted a few best practices that I picked up over the years and got some good feedback. I decided to write them all down in a blogpost. Here goes
Use long options (
logger --priorityvslogger -p). If you're on cli, abbreviations make sense for efficiency. but when you're writing reusable scripts a few extra keystrokes will pay off in readability and avoid ventures into man pages in the future by you or your collaborators.Use
set -o errexit(a.k.a.set -e) to make your script exit when a command fails.Then add
|| trueto commands that you allow to fail.Use
set -o nounset(a.k.a.set -u) to exit when your script tries to use undeclared variables.Use
set -o xtrace(a.k.aset -x) to trace what gets executed. Useful for debugging.Use
set -o pipefailin scripts to catchmysqldumpfails in e.g.mysqldump |gzip. The exit status of the last command that threw a non-zero exit code is returned.#!/usr/bin/env bashis more portable than#!/bin/bash.Avoid using
#!/usr/bin/env bash -e(vsset -e), because when someone runs your script asbash ./script.sh, the exit on error will be ignored.Surround your variables with
{}. Otherwise bash will try to access the$ENVIRONMENT_appvariable in/srv/$ENVIRONMENT_app, whereas you probably intended/srv/${ENVIRONMENT}_app.You don't need two equal signs when checking
if [ "${NAME}" = "Kevin" ].Surround your variable with
"inif [ "${NAME}" = "Kevin" ], because if$NAMEisn't declared, bash will throw a syntax error (also seenounset).Use
:-if you want to test variables that could be undeclared. For instance:if [ "${NAME:-}" = "Kevin" ]will set$NAMEto be empty if it's not declared. You can also set it tononamelike soif [ "${NAME:-noname}" = "Kevin" ]Set magic variables for current file, basename, and directory at the top of your script for convenience.
Summarizing, why not start your next bash script like this:
#!/usr/bin/env bash
# Bash3 Boilerplate. Copyright (c) 2014, kvz.io
set -o errexit
set -o pipefail
set -o nounset
# set -o xtrace
# Set magic variables for current file & dir
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
__base="$(basename ${__file} .sh)"
__root="$(cd "$(dirname "${__dir}")" && pwd)" # <-- change this as it depends on your app
arg1="${1:-}"If you have additional tips, please share and I'll update this post.
