The duality of /bin/sh

A few weeks ago, I ran a shell script on an Ubuntu server and it didn’t produce the same result as on my laptop. The reason for its behavior surprised me.

/bin/sh can point to any other shell

For years, I was used to running scripts with bash or sh. And I had no problems using one or the other. The scripts seemingly had the same behavior. Basically, this might be because the default shell on Debian is bash. Basically, /bin/sh is a symlink to /bin/bash.

But recently, I had some issues with a shell script that was set to use sh. The script looked somewhat like this:

#!/bin/sh

# some commands here
# ...

I’d have expected this to run properly on any system that had bash installed, because that’s what I was used to up to that point.

But after digging through the internet, I found out on newer Ubuntu /bin/sh refers to /bin/dash on Ubuntu. My laptop, which runs Arch Linux, has /bin/sh pointed to /bin/bash. And Debian also has /bin/sh pointed to /bin/bash.

A quick example

bash and dash can make a shell script behave in very different ways despite being the default shells on Debian based Linux distributions. One example of something that works on bash but not on dash is the if [[ .. ]] syntax:

#!/bin/bash

if [[ 1 = 1 ]]; then
    echo 'works on bash'
fi

And the thing is, even if we assume that the script above is called test.sh, running dash test.sh will return an error because dash doesn’t pick up on the #!/bin/bash.

Best practices for shell scripting

Following this, I’ve been consistently using the same shell for all of your work, in my case, that’s bash, partly because it’s the default shell on Arch Linux, which I use daily, but also because it is widely used and even recommended in Google’s shell style guide.