A short rant about #!/bin/sh

This reminds me my start with linux systems. Back then I read some guides how to make some automation scripts and they alway stated to put #!/bin/sh with no explanation what that does. So at the time I took it as some “magic formula” that I don’t have to care about just yet.
Later I found out there are other modifications like #!/usr/bin/env python and that made me wonder what that magic formula actually does.

From that time I use only #!/bin/bash for my scripts (even for POSIX-compliant) because I neve know if I introduce some bashism into the script later (but I know myself enough that I will certainly forget to update shebang).

I hope this will make the frog-monster to ignore me a little while longer. :grinning: :frog:

One question: If the script is not POSIX-compliant is it OK to assume #!/bin/bash is the correct fix or could it be intended for another shell like zsh, fish, …?

No, you can’t assume that. You simply specify the command interpreter in that first line. It doesn’t even have to be a shell, it can be any program that takes standard input. Here is a stupid, but illustrative example:

#!/bin/cat
Hello, world! 

Save this to a file, make it executable and run it :joy_cat:

Now, both Bash and ZSH will interpret POSIX-compliant scripts. They extend the scripting capabilities of POSIX-shells or, in other words, POSIX commands form a subset of Bash commands, and also a subset of ZSH commands. Of course, ZSH will not interpret Bash-specific commands, and vice-versa.

Fish, on the other hand, is not POSIX-compliant or, in other words, a set of all POSIX commands is not a subset of Fish commands. If you run a POSIX script with Fish, you’ll just get a bunch of errors. Fish is only usable as an interactive shell, it’s scripting capabilities, while perfectly fine, are very different from POSIX and thus not portable at all.

So, if you use only POSIX commands, use #!/bin/sh or, even better #!/usr/bin/env sh. If you use Bash-specific commands (with POSIX), use #!/bin/bash (or #!/usr/bin/env bash). And if you use ZSH-specific commands (with POSIX), use #!/bin/zsh (or #!/usr/bin/env zsh).

But whatever you do, do NOT use #!/bin/sh for a Bash script (or ZSH script, but that will likely give you errors), even if seems to work fine (it’s only because on Arch /bin/sh is symlinked to /usr/bin/bash). If you use #!/bin/bash for a POSIX-compliant script, that’s not as bad, but not ideal, because it has to run Bash.

If you’re not sure whether your script is POSIX-compliant or uses Bash-specific commands, use checkbashisms to check. It’s a pretty good tool.

2 Likes

It is pretty rare for anyone to use zsh or fish in a script. If they did, I think there is a high chance they would put the correct interpreter at the top since it wouldn’t even run otherwise.

1 Like

I’m just happy that emacs reads that #!/bin/bash and sets the editing mode according to it. :smile:

1 Like

Yes, likewise for Kate :joy:

1 Like

We have all considered the full posix-bilities in ways we never ere before imagined

1 Like