BASH and Shell

These are the BASH and SHELL language-specific coding styles. Anything mentions here overrides/adds to the "In General" guides.

#1 Shebang Line

Always include Shebang Line in Line 1. Period.. You’ll break your script and let your user crying to figure out which Shell program to use if you avoid it. A Shebang line is:

#!/bin/bash

Example:

#!/bin/bash
1>&2 echo "Hello World"

#2 - Filename

The file extension is .sh or .bash.

#3 - Naming Convention

  • Inherit In General - naming convention.
  • Consistency first.
  • Otherwise, use snake_case convention.
  • Attach package name with double colon (::) for writing a package.


Example 1:

integer=5
export OS_LEVEL=5
TITLE_SHARABLE_VARIABLE="the shared data for other script to source from"

process_data() {
  ...
}

# run
unset integer
process_data

Example 2:

# Single function
my_func() {
  ...
}

# Part of a package
mypackage::my_func() {
  ...
}

#4 - Functions

  • Inherit In-General - Variable and Functions.
  • Opening brace { after the function naming since it breaks the script.
  • export comes after the function declaration.
  • Always keep track to unset your functions after used.

Example:

function_name() {
  echo "Hello World"
}
export -f function_name

#5 - Variables

  • Inherit In-General - Variable and Functions.
  • Keep operations outside variables.
  • export comes before the variable.
  • Forbid array if you it want to be POSIX compliant.
  • Forbid yourself from using local keyword. Use the naming convention for maximum POSIX compatibility.
  • Forbid the use of alias. Use function instead.
  • One exception: use of global variables for configuration is greatly encouraged due to SHELL limitation in object-oriented facility.

Example:

# variable requires operations
GLOBAL_VARIABLE="$(ls)"
export GLOBAL_VARIABLE

# variable with only value
export GLOBAL_LANGUAGE="en-US"

# DO NOT do this. $(...) is an operation
export GLOBAL_VARIABLE="$(ls)"

#6 - Indentation

Rationale

It’s a terminal script.

#7 - If Else and While Loop Condition Syntax

  1. Perferbly [[ ... ]] for bash while [ ... ] for POSIX compliant.
  2. 1 space after [ or [[.
  3. 1 space before ] or ]].
  4. then or do should shares the same line as if, elif, while and for respectively.
  5. No space before the semi-colon (;); 1 space after; then then or do comes later.
  6. All contents inside should have 1 TAB inside.

Example:

# BASH
if [[ 5 != 0 ]]; then
  ...
elif [[ 5 != 0 || 5 != 4 ]]; then
  ...
elif [[ ([[ 5 != 0 || 5 != 4 ]]) && ([[ 5 != 0 || 5 != 4 ]]) ]]; then
  ...
elif [[ ([[ 5 != 0 || 5 != 4 ]]) &&
    ([[ 5 != 0 || 5 != 4 ]]) &&
    ([[ 5 != 0 || 5 != 4 ]]) &&
    ([[ 5 != 0 || 5 != 4 ]]) ]]; then
else
  ...
fi


# POSIX Compliant
if [ -z "$filename" ]; then
  ...
elif [ -z "$filename" ] && { [ -e "$filename" ] || [ -r "$filename" ] }; then
  ...
else
  ...
fi



# BASH
while [[ ([[ 5 != 0 || 5 != 4 ]]) && ([[ 5 != 0 || 5 != 4 ]]) ]]; do
  ...
done

for item in "${list[@]}"; do
  ...
done


# POSIX Compliant
while { [ 5 != 0 ] || [ 5 != 4 ] } && { [ 5 != 0 ] || [ 5 != 4 ] }; do
  ...
done

for file in ./directory/*; do
  ...
done

#8 - Printout (stderr) vs. Output (stdout)

Example:

Add() {
        echo "$((1 + 2))"
        return 0
}

1>&2 echo -n "This is a status message. Doing 5 + 3 = "
Add 5 3

#9 - Command Substitution

  • Use $(...) instead of backtick `...`.
  • Stringtify ( "$(...)" ) the output.

Example:

# This is preferred:
var="$(command "$(command1)")"

# This is not:
var="`command \`command1\``"

# 10 - Built-In or External Commands

  • Use built-in as far as much as possible to reduce dependency.
  • Use "type" commands to find out your keyword nature.

Example:

$ type time
time is a shell keyword
$

That's all for BASH and SHELL script.