Page tree
Skip to end of metadata
Go to start of metadata

Bash Style

  1. Bash is a programming language.  It includes functions.  Shell code outside of functions is effectively code in an implicit main() function.  An entire function should be fully seen on one page (~70-90 lines) and be readily comprehensible.  If you have any doubts, then it is too complicated.  Make it easier to understand by separating it into subroutines.
  2. Length of line
    1. The total length of a line (including comment) must not exceed 80 characters.  Take advantage of bash's += operator for constants or linefeed escapes \.
    2. Lines can be split without the need for a linefeed escape after |, ||, & and && operators.
  3. Indentation
    1. The indentation must 8-column tabs and not spaces. For line continuation, an additional tab should be used to indent the continued line.
  4. Comments are just as important in a shell script as in C code.
  5. Use $(...) instead of `...` for subshell, but avoid them if you can.  Text results from functions should be put into a well-known variable.  Use the subshell syntax only when you have to (e.g. when you need to capture the output of a separate program).  Using the construct with functions leads to stray output and/or convoluted code struggling to avoid output pollution.  It is also more computationally efficient to not fork() the BASH process. BASH is slow enough already.
    1. `...` is obsolete and $(...) is easier to see the start and end of the subshell command, avoids confusion with '...' and a small font, and $(...) can be nested
  6. Use boolean values
    1. If a variable is intended to be used as a boolean, then it must be assigned as followed:

local mybool=false         # or true
if ${mybool}; then

  1. Use "export FOOBAR=val" instead of "FOOBAR=val; export FOOBAR" for clarity and simplicity
  2. Use [[ expr ]] instead of [ expr ], especially since the [[ test understands regular expression matching with the "=~" operator.  The easiest way to use it is by putting the RE in a variable and expanding the RE after the operator without quotes.
  3. Use $((...)) for arithmetic expressions instead of expr

Test Framework

  1. Variables
    1. Names of variables local to current script which are not exported to the environment should be declared with "local" and use lowercase letters
    2. Names of global variables or variables that exported to the environment should be uppercase letters
  2. Functions
    1. Each functions must have a section describing what it does and explain the list of parameters

      # One- or two-line description of this function's purpose
      # usage: function_name [--option argument] {required_argument} ...
      # option: meaning of "option" and its argument
      # required_argument: meaning of "required_argument"
      # expected output and/or return value(s)
  3. Tests and Libraries
    1. To avoid clustering a single file, there should be a <test-lib>.sh file for each test that contains specific functions and variables for that test.
    2. Any functions, variables that global to all tests should be put in
    3. A test file only need to source and necessary <test-lib>.sh file
  4. Test script layout
  • No labels


  1. Prefer 'if ! [[ $x = $y ]]; then error "x != y"; fi' to 'if [[ $x != $y ]]; then error "x != y"; fi'. Since the second form gives a false pass when x or y is not initialized correctly.

    1. test "X$x" = "X$y" || die 'x and y differ'

      There are several reasons why it is helpful to do string comparisons using a prefix and quoting them.  The reasons are numerous and do not go away for different flavors of "test".