Bash
Check out The Bash Hackers Wiki 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 Mode 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
- gum
- Prettier CLI
- bashsimplecurses
- Easier library for curses, i.e. windows in the terminal
- shunit2
- xUnit-based unit test framework for bash scripts