For some small tasks, sometimes Bash script (shell script in general) is better than a full-blown program using programming languages. Here are some personal tips to write a Bash script:

Exit on fail

Use set -o errexit to make the script exit when it fails. If some commands are allowed to fail, command1 || echo "command1 is failed, but continuing" can be used.

Prevent access to undeclared variables

Use set -o nounset to exit when the script tries to use undeclared variables. Imagine running this command when undeclared variables is allowed:

rm -rf ${base_folder}/*

When the variable $base_folder is not set, it will become rm -rf /*. If some variables are allowed to be undeclared, use ${variable_name:default_value} to set $variable_name to default_value when it’s not declared.

Idempotency

What is idempotency?

Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.

In short, it means that idempotent Bash scripts should have the same effects on the system even when called multiple times. Some example of idempotency in Bash script:

The basic syntax of creating a symbolic link is:

ln -s source target

This is not idempotent, it will fail in the second run because the target is already exists. It can be solved by adding the -f flag:

ln -sf source target

If executed multiple times, it’s still not idempotent because it will create a symbolic link inside the previously created symbolic link (nested). The idempotent way to create a symbolic link is:

ln -sfn source target

Removing a file

The command rm filename will fail if the file does not exist. Use rm -f instead. To remove directory, use rm -rf instead.

Downloading a file

Common usage is to download a file if only it does not exist:

if [[ ! -f ${HOME}/.local/bin/random_binary ]]; then
  wget -qO ${HOME}/.local/bin/random_binary https://randomsite.com/random_binary
fi

Use curly brace when using variable inside a string

When using variables inside a string, sometimes it’s clearer to access the variable with the curly brace. So instead of this:

echo "$var1_new.yaml"

Prefer this:

echo "${var1}_new.yaml"

So it’s clear that the variable name is var1, not var1_new.