Bashisms are bash extensions that are not strictly POSIX compliant. Using some of these extensions can lead to portability issues between different shells.

Since Ubuntu 6.10, the default system shell, /bin/sh, was changed to dash. This change will cause /bin/sh scripts to fail if bash extensions exist.

There is a tool called checkbashisms that is shipped along with the “devscripts” package, which is able to find several kind of bashisms in /bin/sh scripts and makefiles.

Install checkbashisms
First, check if checkbashisms is installed using the following command:

$ aptitude show devscripts
Package: devscripts
State: not installed
Version: 2.10.11ubuntu5.8.04.2
Priority: optional
Section: devel
Maintainer: Ubuntu Core Developers
Uncompressed Size: 1274k
Depends: debianutils (>= 2.0), dpkg-dev, libc6 (>= 2.1.3), perl (>= 5.8), sed (>= 2.95), wget | curl
Recommends: debhelper, fakeroot
Suggests: at, build-essential, cvs | subversion | svk | tla | bzr | git-core | mercurial, cvs-buildpackage, dctrl-tools, debian-keyring, devscripts-el, dupload (>= 2.1) | dput, gnupg (>= 1.0.7), gnuplot, libcrypt-ssleay-perl,
libdigest-md5-perl, libfile-desktopentry-perl, libsoap-lite-perl, libtimedate-perl, liburi-perl, libwww-perl, lintian | linda, mailx | mailutils, man-db, mutt, patch, patchutils, ssh, strace, wdiff, wget,
Conflicts: debmake (< 3.5), dupload (< 2.1), kdesdk-scripts (< 4:3.5.6-2), suidmanager (< 0.51) Description: Scripts to make the life of a Debian Package maintainer easier Contains the following scripts, dependencies/recommendations shown in brackets afterwards: * annotate-output: run a command and prepend time and stream (O for stdout, E for stderr) for every line of output * archpath: print tla/Bazaar package names [tla | bazaar] * bts: a command-line tool for manipulating the BTS [www-browser, libsoap-lite-perl, libwww-perl, mailx | mailutils] * chdist: tool to easily play with several distributions [dctrl-tools] * checkbashisms: check whether a /bin/sh script contains any common bash-specific contructs * cvs-debi, cvs-debc: to call debi and debc from the CVS working directory after running cvs-debuild or cvs-buildpackage [cvs-buildpackage] * cvs-debrelease: to call debrelease from the CVS working directory after running cvs-debuild or cvs-buildpackage [cvs-buildpackage, dupload | dput, ssh] * cvs-debuild: run cvs-buildpackage using debuild (see below) as the package building program [cvs-buildpackage, fakeroot, lintian | linda, gnupg] * dd-list: given a list of packages, pretty-print it ordered by maintainer * debc: display the contents of just-built .debs * debchange/dch: automagically add entries to debian/changelog files [wget, liburi-perl] * debcheckout: checkout the development repository of a debian package * debclean: purge a Debian source tree [fakeroot] * debcommit: commit changes to cvs, svn, svk, tla, bzr, git, or hg, basing commit message on changelog [cvs | subversion | svk | tla | bzr | git-core | mercurial] * debdiff: compare two versions of a Debian package to check for added and removed files [wdiff, patchutils] * debi: install a just-built package * debpkg: dpkg wrapper to be able to manage/test packages without su * debrelease: wrapper around dupload or dput [dupload | dput, ssh] * debsign, debrsign: sign a .changes/.dsc pair without needing any of the rest of the package to be present; can sign the pair remotely or fetch the pair from a remote machine for signing [gnupg, debian-keyring, ssh] * debuild: wrapper to build a package without having to su or worry about how to invoke dpkg to build using fakeroot. Also deals with common environment problems, umask etc. [fakeroot, lintian | linda, gnupg] * deb-reversion: increases a binary package version number and repacks the archive * desktop2menu: produce a skeleton menu file from a desktop file [libfile-desktopentry-perl] * dget: downloads Debian source and binary packages [wget] * dpkg-depcheck, dpkg-genbuilddeps: determine the packages used during the build of a Debian package; useful for determining the Build-Depends control field needed [build-essential, strace] * dscverify: verify the integrity of a Debian package from the .changes or .dsc files [gnupg, debian-keyring, libdigest-md5-perl] * grep-excuses: grep the update_excuses.html file for your packages [wget] * licensecheck: attempt to determine the license of source files * list-unreleased: searches for unreleased packages * manpage-alert: locate binaries without corresponding manpages [man-db] * mass-bug: mass-file bug reports [mailx | mailutils] * mergechanges: merge .changes files from a package built on different architectures * nmudiff: mail a diff of the current package against the previous version to the BTS to assist in tracking NMUs [patchutils, mutt] * plotchangelog: view a nice plot of the data in a changelog file [libtimedate-perl, gnuplot] * pts-subscribe: subscribe to the PTS for a limited period of time [mailx | mailutils, at] * rc-alert: list installed packages which have release-critical bugs [wget] * rmadison: remotely query the Debian archive database about packages [wget, liburi-perl] * svnpath: print svn repository paths [subversion] * tagpending: shell script which runs from a Debian source tree and tags bugs that are to be closed in the latest changelog as pending. [wget, liburi-perl] * uscan: scan upstream sites for new releases of packages [libcrypt-ssleay-perl, libwww-perl] * uupdate: integrate upstream changes into a source package [patch] * whodepends: check which maintainers' packages depend on a package * who-uploads [gnupg, debian-keyring, wget]: determine the most recent uploaders of a package to the Debian archive * wnpp-alert: list installed packages which are orphaned or up for adoption [wget] Also included are a set of example mail filters for filtering mail from Debian mailing lists using exim, procmail, etc.

Since in our case it is not installed, we will install checkbashisms using the following command:

$ sudo aptitude -y install devscripts

Using checkbashisms
Once you have the devscripts package installed, you can check for bashisms in scripts using the the following command:
$ checkbashisms [-n] [-f] [-x] script_filename
For example, to check for bashisms in the start-up script for Appistry CloudIQ cloud platform, use the following command:

$ checkbashisms -f /etc/init.d/fabric_keeper

The above command returns the following output:

possible bashism in /etc/init.d/fabric_keeper line 29 (ulimit):
ulimit -c unlimited
possible bashism in /etc/init.d/fabric_keeper line 95 (kill -[0-9] or -[A-Z]):
kill -15 `cat $FABRIC_HOME/$`
possible bashism in /etc/init.d/fabric_keeper line 103 (let …):
let counter=counter+1
possible bashism in /etc/init.d/fabric_keeper line 104 (kill -[0-9] or -[A-Z]):
[ -r $FABRIC_HOME/$ ] && kill -0 `cat $FABRIC_HOME/$ 2>/dev/null` 2>/dev/null

Checkbashisms provides a good starting point to find bash extensions in /bin/sh scripts. Using this tool, you should be well on your way to getting rid of these bash extensions and towards creating portable scripts.

To learn more about bashisms see