Why You Should Use ‘sh’ Syntax Instead of Defaulting to ‘bash’

We are unknowingly doing a mistake in writing our linux shell scripts, and most often we are not paying attention to the syntax according to it’s interpreter. Consider the shell script below:

#!/bin/sh
service=myservice
if [ "$1" == "install" ]
then
        echo "Installing $service to boot"
        cp $service /etc/init.d
        update-rc.d $service defaults
elif [ "$1" == "remove" ]
then
        echo "Removing $service from boot"
        update-rc.d $service disable
        update-rc.d -f $service remove
        rm -f /etc/init.d/$service
else
        echo "Usage: ./install.sh [install|remove]"
fi

It is a very naïve and simple script to install a myservice script at boot (or to remove it). For a casual personal thing, this looks all good right? Great, let’s execute this as ./test.sh and you get:

./test.sh: 3: [: unexpected operator
./test.sh: 8: [: unexpected operator
Usage: ./install.sh [install|remove]

The reason for this error is that the interpreter sh is looking for the operator of comparison '=' but the operator we all get taught for comparison is '=='. The use of the interpreter sh was decided at the topmost line called the shebang line.

Now we have two solutions in front of us. Either fix the syntax according to sh or use a more modern and elaborated bash which works according to the syntax you are more familiar with. A quick google search tells you that “just use bash” is the popular answer and the straight answer is lingering down somewhere on the mighty stackoverflow.

I am making a case that we should try to stick to sh as much as possible and cave in to use bash only when the requirement has complexity which asks for it. Let’s take a look.

sh is Omnipresent

sh offers better portability across all linux distributions and that is because they all are required to have sh. In other words, sh is omnipresent! If you have ever broken your system while fiddling with it, you must have been thrown in this cold dark place with a monochrome shell. Yup, that’s sh.

Linux boot emergency rescue mode

When your system enters emergency mode, it has loaded nothing, has mounted nothing, started no services. But, at-least in that broken state it has got sh for you so that you can fix whatever shenanigans you have done in boot scripts. How about that?

So is there some kind of rule or standard or norm, that barring other things, sh has to be there on a linux system? Well it is what is called a “POSIX Standard”

sh is Standard

The syntax of sh is very minimal. This allows for a professional scripting person to remember the entirety of it more easily. A glaring example is that it doesn’t support arrays. This is because sh is standardized and pans even outside to unix. In fact, that is where sh has come from. It is also known as Bourne shell named after the programmer who made it (and thankfully didn’t call it bs). The knowledge that a certain thing is a standard definitely gives a bit of comfort.

Being the minimal program in itself, it is also low on resources. I would make this a bigger point but newer better shells have come along (e.g. dash) which are lower on resources. And in fact, some systems simply link sh to dash or to bash. Which takes us to the next point …

sh Syntax is a Subset

For various reasons, some linux distributions do not package sh at all and simply link sh to bash and call it a day. In other words, there is no sh. You may have been using sh on that system, but it was bash all along.

I found this immediately funny until immediately I didn’t. Any shell will be a superset of sh which means whatever shell your system is replacing sh with, has the obligation of supporting sh syntax. This makes a very good compatibility point that you have maximum of it, backwards or forwards, if your scripts are written in sh.

Conclusion

So that was my case for adhering to sh syntax with the #!/bin/sh shebang line up top when you are writing any shell scripts on a linux system. Yes, at times your requirement will be complex enough that bash with its fancy arrays, simpler conditional syntax and many more things, will seem like the best choice. No denying that. And if things are going complex enough, then you should assess if an outsider python is the right candidate, because that really opens up the possibilities of handling complexities.

But for all practical purposes and everyday shell scripting, bourne shell’s syntax should be the way to go. If your complexity increases mid way, you can always switch it up to bash and whatever you have already written will continue to work by design.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.