While creating SkyHole, I found myself writing a few shell scripts. They get the job done, and although I could have written them in a language such as Ruby or Python, it's a safe bet to make that any UNIX machine that execute these scripts have a shell.
As I was writing these scripts, it became clear that out of the box, a shell script doesn't have the niceties that you might expect when coming from another language. Things such as the script exploding when a variable isn't defined or the script exiting when a step in the function has failed aren't handled normally in a shell script. The purpose of this post is to share a few tricks to make scripting in a shell a bit safer.
Have a shebang
Not every machine a script runs on might have an up to date version of bash
at /bin/bash
. For example, macOS ships with an old version on this path.
#!/usr/bin/env bash
Set the exception parameter
If a script fails at a certain point, what would you like to happen? Most of the time, you want it to stop and not continue because the rest of the script might depend on that command to succeed. You can tell the shell to exit if anything throws an error immediately, and therefore the rest of the script won't continue running.
set -e
If you want to take this a step further, you can add -o pipefail
, which protects against any failure anywhere in a pipeline, rather than just the last command.
set -eo pipefail
Set the undefined parameter
A script might rely on user input or data from another source to run correctly. What happens when that data is empty, and a variable never gets set? Nothing. The script will continue and fail only when an empty input is invalid for that command. What about when you interpolate a path? For example:
rm -rf "${USER_FOLDER}/"
What's going to happen here if the variable USER_FOLDER
is never set? You guessed it; the shell will interpret that command as rm -rf "/"
. That would not be very good. You can prevent this from happening by adding the following to the top of your scripts.
set -u
Conclusion
What does this look like all together? I always add these two lines to the top of every shell script I write.
Hint: you can combine multiple set
parameters.
#!/usr/bin/env bash
set -euo pipefail
Check out Anybody can write good bash (with a little effort) for more tips and tricks when scripting in shell. It was the inspiration for this post.
Top comments (0)