The Goo Software Blog

All The Goo That's Fit To Print

Bashisms – a Note on Creating Portable Shell Scripts

Earlier this week I finally scratched a long-standing itch and wrote a shell script for automating the fetching of gitignore boilerplates from GitHub’s gitignore library. It’s called gibo, and it works like this:

$ gibo Python vim OSX >> .gitignore

That line will squirt the GitHub gitignore templates for Python, vim and OSX into my .gitignore file. Nifty eh?

Having scratched the itch I did what any good itch-scratcher would do and uploaded it to GitHub. The Changelog blog picked up on it and it got a load of downloads. Cool!

And eventually, it got a pull request. Even better! I love it when my peers help to improve my code! The pull request read as follows:

if [ $# == 0 ] ; then
  # ...
fi

The above works in BASH (or probably similar shells). But it fails on DASH (default sh in debian).

This pull request fixes this.

It turns out that == is a ‘bashism’; a non-POSIX-compliant construct only supported by bash and a handful of other shells, but not by all. Bashisms are bad; they make your script less portable. gibo’s shebang line tells it to run using /bin/sh, and on some flavours of Debian that’s an alias for /bin/dash.

I fixed the bug, but it left me wondering whether there were any other bashisms in my script. Then I came across checkbashisms, a script that answers exactly that question. Here it is running on gibo before that pull request was raised:

$ checkbashisms gibo
possible bashism in gibo line 103 (should be 'b = a'):
if [ $# == 0 ]; then
possible bashism in gibo line 114 (should be 'b = a'):
    if [ $( echo $opt | cut -c1) == "-" ]; then
possible bashism in gibo line 121 (should be 'b = a'):
if [ $has_opts == 1 -a $has_args == 1 ]; then
possible bashism in gibo line 121 (should be 'b = a'):
if [ $has_opts == 1 -a $has_args == 1 ]; then

And here it is running on the latest version:

$ checkbashisms gibo

Perfect!

If you’re writing shell scripts and distributing them, checkbashisms is your friend! Check it out. (If you’re on Debian/Ubuntu you can install it as part of the devscripts package with apt-get install devscripts, otherwise you can just download the script from SourceForge and copy it to somewhere on your $PATH.)