Skip to content

Bash Style guide

serverco edited this page Nov 7, 2016 · 2 revisions

bash style guide

This document is so that others can collaborate with me in my open source projects. It's primarily based on http://wiki.bash-hackers.org/scripting/style along with my own experiences over the years.

Keep in mind this is not for general shell scripting, these are rules specifically for Bash and can take advantage of assumptions around Bash as the interpreter.

Summary

  • Indent code using 2 spaces.
  • Always double quote variables, including subshells. No naked $ signs
  • Never use deprecated style. Most notably:
    • Define functions as myfunc() { ... }, not function myfunc { ... }
    • Always use [[ instead of [ or test
    • Never use backticks, use $( ... )
  • Use mktemp for temporary files, always cleanup with a trap.
  • Prefer absolute paths (leverage $PWD), always qualify relative paths with ./.

Best Practices and Tips

  • Use Bash variable substitution if possible before awk/sed.
  • Generally use double quotes unless it makes more sense to use single quotes.
  • For simple conditionals, try using && and ||.
  • Don't be afraid of printf, it's more powerful than echo.
  • Put then, do, etc on same line, not newline.
  • Skip [[ ... ]] in your if-expression if you can test for exit code instead.
  • Use .sh or .bash extension if file is meant to be included/sourced. Never on executable script.
  • Put complex one-liners of sed, perl, etc in a standalone function with a descriptive name.
  • Design for simplicity and obvious usage.
    • Avoid option flags and parsing, try optional environment variables instead.
    • Use subcommands for necessary different "modes".
  • Be conscious of the need for portability.

Good References and Help

Indentation (2 spaces)

Indentation is nothing that technically influences a script, however with 2 spaces

  • it's easy and fast to type
  • it's not a hard-tab that's displayed differently in different environments
  • it's wide enough to give a visual break and small enough to not waste too much space on the line

tabs should be avoided other than in here-document where it helps the indentation.

Breaking compound commands

Put the introducing keyword and the initial command list or parameters on one line ("head") Indent the body statements within the command Put the closing keyword on a separated line, indented like the initial introducing keyword

examples ....

if, then

if ...; then
  ...
elif ...; then
  ...
else
  ...
fi

for

for f in /etc/*; do
  ...
done

while/until

while [[ $answer != [YyNn] ]]; do
  ...
done

Readability - Cryptic constructs

Cryptic constructs, we all know them. If they are not 100% needed, avoid them, since nobody except you may be able to decipher them.

If you need to use a cryptic construct, include a comment that explains in detail what your "monster" does.

Ensure your code is readable - an example from http://mywiki.wooledge.org/BashGuide/Practices

This first version of code would work ....

   1 x=(       Marcus\ The\ Rich JJ\ The\ Short
   2   Timid\ Thomas Michelangelo\ The\ Mobster)
   3 for name in "${x[@]}"
   4   do if [ "$name" = "$x" ]; then echo $name was my first friend.
   5  elif
   6    echo $name    |   \
   7   grep -qw Short
   8     then echo $name is a shorty.
   9  elif [ "x${name:0:1}" = "xM" ]
  10      then echo $name starts   with an M; else
  11 echo I kind of forgot what $name \
  12  is like.; fi; done

This second version is much easier to read, and still works :) so please use something closer to this second version.

   1 friends=( "Marcus The Rich" "JJ The Short" "Timid Thomas" "Michelangelo The Mobster" )
   2
   3 # Say something significant about my friends.
   4 for name in "${friends[@]}"; do
   5
   6     # My first friend (in the list).
   7     if [[ $name = "${friends[0]}" ]]; then
   8         echo "$name was my first friend."
   9
  10     # My friends whose names start with M.
  11     elif [[ $name = M* ]]; then
  12         echo "$name starts with an M"
  13
  14     # My short friends.
  15     elif [[ " $name " = *" Short "* ]]; then
  16         echo "$name is a shorty."
  17
  18     # Friends I kind of didn't bother to remember.
  19     else
  20         echo "I kind of forgot what $name is like."
  21
  22     fi
  23 done