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