“!#/bin/sh” what does this mean?

Nephi Szvoboda
4 min readDec 21, 2022

--

While attempting to write an article to explain an automated bash script line by line I got hang up on one of the very first line !#/bin/sh . I have seen this many times being used but never really bothered to try and understand it. While researching this topic I came across this stackoverflow answer and I have taken a lot of the source material verbatim.

POSIX — The Portable Operating System Interface (POSIX) is a family of standards specified by the IEEE Computer Society for maintaining compatibility between operating systems.

sh — or the Shell Command Language is a programming language described by the POSIX standard. It has many implementations (ksh88, Dash, ...).

Because sh is a specification, not an implementation, /bin/sh is a symlink (or a hard link) to an actual implementation on most POSIX systems.

bash — bourne again shell developed by Brian Fox released in 1989 serving as a superset of the sh specification.

Bash started as an sh-compatible implementation (although it predates the POSIX standard by a few years), but as time passed it has acquired many extensions. Many of these extensions may change the behavior of valid POSIX shell scripts, so by itself Bash is not a valid POSIX shell. Rather, it is a dialect of the POSIX shell language.

Bash supports a --posix switch, which makes it more POSIX-compliant. It also tries to mimic POSIX if invoked as sh.

What is sh?

sh (or the Shell Command Language) is a programming language described by the POSIX standard. It has many implementations (ksh88, Dash, ...). Bash can also be considered an implementation of sh (see below).

Because sh is a specification, not an implementation, /bin/sh is a symlink (or a hard link) to an actual implementation on most POSIX systems.

What is Bash?

Bash started as an sh-compatible implementation (although it predates the POSIX standard by a few years), but as time passed it has acquired many extensions. Many of these extensions may change the behavior of valid POSIX shell scripts, so by itself Bash is not a valid POSIX shell. Rather, it is a dialect of the POSIX shell language.

Bash supports a --posix switch, which makes it more POSIX-compliant. It also tries to mimic POSIX if invoked as sh.

sh = bash?

For a long time, /bin/sh used to point to /bin/bash on most GNU/Linux systems. As a result, it had almost become safe to ignore the difference between the two. But that started to change recently.

Some popular examples of systems where /bin/sh does not point to /bin/bash (and on some of which /bin/bash may not even exist) are:

  1. Modern Debian and Ubuntu systems, which symlink sh to dash by default;
  2. Busybox, which is usually run during the Linux system boot time as part of initramfs. It uses the ash shell implementation.
  3. BSD systems, and in general any non-Linux systems. OpenBSD uses pdksh, a descendant of the KornShell. FreeBSD's sh is a descendant of the original Unix Bourne shell. Solaris has its own sh which for a long time was not POSIX-compliant; a free implementation is available from the Heirloom project.
  4. MacOs has switched their default shell from bash to zsh since MacOs Cataline (2019). source

To better understand the difference between zsh and bash I found a good answer on apple.stackexchange and another article by geeksforgeeks.

Shebang line

Ultimately, it’s up to you to decide which one to use, by writing the «shebang» line as the very first line of the script.

E.g.

#!/bin/sh

will use sh (and whatever that happens to point to),

#!/bin/bash

will use /bin/bash if it's available (and fail with an error message if it's not). Of course, you can also specify another implementation, e.g.

#!/bin/dash

Which one to use

A recommendation would be to use sh for the following reasons:

  • it is standardized
  • it is portable across POSIX systems — even if they happen not to have bash, they are required to have sh

There are advantages to using bash as well. Its features make programming more convenient and similar to programming in other modern programming languages. These include things like scoped local variables and arrays. Plain sh is a very minimalistic programming language.

Key differences between SH and bash

Sources

--

--