write safe shell scripts set -euf set -o pipefail

et -euf -o pipefail
In dash, set -o doesn't exist, so use only set -euf.
What do those do?

set -e

If a command fails, set -e will make the whole script exit, instead of just resuming on the next line. If you have commands that can fail without it being an issue, you can append || true or || : to suppress this behavior — for example set -e followed by false || : will not cause your script to terminate.

set -u

Treat unset variables as an error, and immediately exit.

set -f

Disable filename expansion (globbing) upon seeing *?, etc..
If your script depends on globbing, you obviously shouldn't set this. Instead, you may find shopt -s failglob useful, which causes globs that don't get expanded to cause errors, rather than getting passed to the command with the * intact.

set -o pipefail

set -o pipefail causes a pipeline (for example, curl -s http://sipb.mit.edu/ | grep foo) to produce a failure return code if any command errors. Normally, pipelines only return a failure if the last command errors. In combination with set -e, this will make your script exit if any command in a pipeline errors.

Quote liberally

Whenever you pass a variable to a command, you should probably quote it. Otherwise, the shell will perform word-splitting and globbing, which is likely not what you want.
For example, consider the following:
alex@kronborg tmp [15:23] $ dir="foo bar"
alex@kronborg tmp [15:23] $ ls $dir
ls: cannot access foo: No such file or directory
ls: cannot access bar: No such file or directory
alex@kronborg tmp [15:23] $ cd "$dir"
alex@kronborg foo bar [15:25] $ file=*.txt
alex@kronborg foo bar [15:26] $ echo $file
bar.txt foo.txt
alex@kronborg foo bar [15:26] $ echo "$file"
*.txt
Depending on what you are doing in your script, it is likely that the word-splitting and globbing shown above are not what you expected to have happen. By using "$foo" to access the contents of the foo variable instead of just $foo, this problem does not arise.
When writing a wrapper script, you may wish pass along all the arguments your script received. Do that with:
wrapped-command "$@"
See "Special Parameters" in the bash manual for details on the distinction between $*$@, and "$@" — the first and second are rarely what you want in a safe shell script.

Comments

Popular posts from this blog

HAproxy logging

tomcat catalina coyote jasper cluster

NFS mount add in fstab _netdev instead of default | firewall-cmd --list-all