Bash Tips

Bash Tips

Overview

This post simply provides a grab bag of bash snippets that are unrelated and not enough to write a whole post on. Enjoy!

Redirects

All those fun redirect operators are outlined really well in this Stack Overflow post.

Grep, Awk, and Sed

Grep is one of the most flexible and useful Linux utilities, Awk is actually a full blown programming language, and Sed isn’t too bad either. This 9 page overview gives some good tips to get started without being overly long and verbose.

Comparison Operators

The cases of comparing strings versus comparing variables are handled a little differently in bash. This is an excellent guide. Note the whitespace! Bash is particular about whitespace.

Checking if a Variable is Empty

Example:

if [ -z "$var" ]
then
    # var is empty
else
    # var is not empty
fi

Checking Exit Codes

The proper way to check out an exit code is C-style, and can be a little confusing. Example stolen from this Stack Overflow post.

if some_command
then
    # command returned true
else
    # command returned some error
fi

or inverted:

if ! some_command
then
    # command returned some error
else
    # command returned true
fi

Checking Apt Versions

Ex.

$ apt-cache policy libgtest-dev
libgtest-dev:
  Installed: 1.7.0-4ubuntu1
  Candidate: 1.7.0-4ubuntu1
  Version table:
 *** 1.7.0-4ubuntu1 500
        500 http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages
        100 /var/lib/dpkg/status

Here the version is 1.7.0-4ubuntu1 and this version can be installed by running:

apt-get install libgtest-dev=1.7.0-4ubuntu1

Checking the Beginning of a Large File

In a simple case, head is useful:

# This gives the first ten lines
head large_file 

# This gives the first 25 lines
head -25 large_file 

For more complicated cases head has other flags, or you can use cut:

# This gives the first 100 bytes
head -c 100 large_file 

# This gives the first 100 characters 
# (useful for debugging JSON loading errors!)
cut -c1-100 < large_file

# The above command is equivalent to
cat large_file | cut -c1-100

# But avoids the useless cat

Custom logging statements

A practice I am in the habit of is placing a variable at the top of scripts called MYFILENAME. I have found it useful for logging and usage statements.

MYFILENAME="myscript.sh"

# LINENO is built in 
echo "[INFO: $MYFILENAME: $LINENO] Starting myscript.sh"

This becomes helpful when you have large and complicated bash scripts that need to work together.

Casing Arguments

This has worked well for me to case out command line args. You may need other checks to ensure the correct variables were passed in. If you pass in an extra arg thats not supported this does not catch it. This example is something I commonly have to parse out for deployment scripts. If the flag --dev is found, I set a DEV flag to true, etc.

# While there are still arguments to parse
while [[ $# -gt 0 ]]
do
key="$1"

# Case them out
case $key in
    --dev)
    DEV=true
    shift
    ;;
    --prod)
    PROD=true
    shift
    ;;
esac
done

Figuring Out Where Your File Is

You want someone to be able to run your script from multiple locations, but the script may need to move around within a repository to access different files. A simple and relatively robust way to manage this is by figuring out the directory your script is located in, and cd-ing to that directory. This snippet should take care of that.

This works by getting the script name from $0. For a more in depth discussion of this, see this SO post. For a very in depth discussion of the portability of this command and other options, see this SO post.

cd $(dirname "$0")

Using Shellcheck

If you have never used it, shellcheck is a fantastic shell linter. Install and set up is easy, there is no reason not to use it. I find it to be accurate and helpful, and definitely not too picky.

Iterating Over an Array

I always forget the syntax for this, so here is an example:

SAMPLE_LIST=(
    "list item 1"
    "list item 2"
)


for item in "${SAMPLE_LIST[@]}"
do
    # Access the item like this
    echo "${item}"
done

Bash array reference

This is a great reference for bash arrays:

https://tldp.org/LDP/abs/html/arrays.html