I recently erased part of my home directory with a shell script I wrote. Fortunately, I did hit Ctrl-C fast enough to avoid the worst.
My mistake h
A couple of ideas:
Use -e
flag in the shebang, for example #!/bin/sh -e
. That way the script will stop at the first error. It's a bit like throwing a RuntimeException
in Java. This probably did save my ass a couple of times, and I have a feeling it would helped you too in this case.
Handle the exit codes of all the statements in your scripts. Actually using -e
in the shebang will force you to do this.
Don't chain commands with ;
. Use &&
instead. Again, using -e
in the shebang will force you to do this.
Properly quote paths that might contain spaces or other special characters.
It's best if a script doesn't do dangerous things when used without parameters.
For non-trivial scripts, make sure to -h
and --help
flags that print a helpful message. (I use this script to generate scripts with flag parsing.) This should be mandatory for scripts that can do dangerous things when called without parameters.
Exit your scripts with an explicit exit 1
on any non-normal exit. It's a common mistake to handle an error in an if
block, echo
some helpful message, and then exit
without any arguments. Since exit
uses the exit code of the last command, in this case echo
, it will exit with success. Note that in the sample script I linked earlier, I exit 1
after printing the help message when handling the --help
flag.
If you don't need bash
features, use a #!/bin/sh
shebang and try to stay compatible with older versions. Being portable is a kind of robustness, I think.
Use $()
instead of ``
. Easier to read ~~ harder to make mistakes.
Format your code nicely and consistently. Easier to read ~~ robustness.
Be aware of the differences between platforms. For example both date --iso
and date +%F
print dates in the format 2013-11-17
, but the first only works in GNU systems, the second works in BSD and Solaris too. So use date +%F
always, it works everywhere. There are of course 100s of examples like this. If you're doing something you're not used to every day, try to check if it works in a different system too.
Test for empty variables, especially in dangerous commands like rm -fr
. For example the result of rm -rf "$TOPDIR/$OBJDIR"
can be disastrous if TOPDIR or/and OBJDIR happens to be empty or unset. In general, double-check or triple check the possible parameter values of dangerous commands like this.
Don't push the limits of shell scripts. Scripts are supposed to be glue-code. If you catch yourself doing something tricky, or that you need obscure features, chances are you're better off moving to more powerful languages.
In the end, none of this will prevent you from making stupid mistakes.
PS: I will keep coming back and add more things as I remember them. Please feel free to suggest improvements and I'll add them. Thanks.