Bash

Check out The Bash Hackers Wikiopen in new window to learn more advanced syntax/patterns.

Style

The style I aim for, anyway. There's no official guide.

  • Max line length is 110 characters.
    • 80 would be more traditional, but this looks ridiculous on any reasonably-sized screen. We ain't in the 80s anymore.
  • Shebang should be /usr/bin/env bash unless you need to ignore the user's environment, in which case /bin/bash for portability.
  • Use Bash Strict Modeopen in new window to avoid skipping over errors:
# Exit the script if there's an error
set -e

# Error out if a variable is undefined
set -u

# Prevent errors from *within* a pipeline from being masked
# (The last command's return code is the entire pipeline's otherwise)
set -o pipefail

# Fail if a glob doesn't match anything
shopt -s failglob
  • To debug your script:
# Print each command as it's being run
set -x

# Remove the '+' if you don't like that, or just add the character(s) you'd like instead
export PS4=""
  • Each script should start with a description block, with the top and bottom delimiters being 80 # characters.
################################################################################
#
# This script re-mounts the given tmpfs with the `noexec` option
#
################################################################################
  • Denote each section with a description block as needed, with the top and bottom delimiters being 50 # characters.
##################################################
#
# Utility functions
#
##################################################
  • Variable and function names should be snake_case.
function list_fs() { : }
  • Indentation should be two spaces.
function list_fs() {
  fs_type="${1:-tmpfs}"
  df -hT | grep --color=none tmpfs
}
  • A function's contents should have a newline after the opening bracket and before the closing bracket.
    • Sometimes I skip this if the function doesn't have a lot of content, i.e. <= 3 lines, but to illustrate...
function list_fs() {

  fs_type="${1:-tmpfs}"
  df -hT --type=$fs_type | tail -n +2 | awk '{ print $7 }'

}
  • Avoid parameter expansion by always quoting your variables (with curly braces):
function list_fs() {

  fs_type="${1:-tmpfs}"
  df -hT --type="${fs_type}" | tail -n +2 | awk '{ print $7 }'

}
  • Document your functions' arguments and return types.
    • I use a slightly modified form of Google's Python docstring style because I like how it looks.
    • Of course, make sure you document your code in general! Bash is whack, so it needs explanation.
# List all mounted filesystems of a given type.
#
# Args:
#   $1 - Filesystem type. Defaults to 'tmpfs'.
#
# Returns:
#   A newline-delimited list of filesystems of the given type.
#
function list_fs() {

  fs_type="${1:-tmpfs}"

  # Return just the FS names
  df -hT --type="${fs_type}" | tail -n +2 | awk '{ print $7 }'

}
  • If you want a function's return value in a variable, you can follow this pattern:
function list_fs() {

  fs_type="${1:-tmpfs}"
  RETVAL=$(df -hT --type="${fs_type}" | tail -n +2 | awk '{ print $7 }')

}

list_fs
echo "${RETVAL}"

Tools

Last Updated: