53

In most shell scripts I've seen (besides ones I haven't written myself), I noticed that the shebang is set to #!/bin/sh. This doesn't really surprise me on older scripts, but it's there on fairly new scripts, too.

Is there any reason for preferring /bin/sh over /bin/bash, since bash is pretty much ubiquitous, and often default, on many Linux and BSD machines going back well over a decade?

  • 23
    It's a good partice to use /bin/sh if you do not use specific bash functions. One day you could have to use one of your script on a system on which it is not installed (remote server, embedded computer...) – Mathieu Dec 22 '15 at 13:52
  • 1
    in general you should avoid asking questions which lend themselves to answers based on opinion (which is the only possible way i believe this question can be answered - but that's just my opinion). – mikeserv Dec 22 '15 at 16:31
  • 9
    I believe that it is possible to answer this question without involving mere opinion, by pointing to at least two organizations that addressed this very thing over a number of years, and looking at the history and outcome. With plenty of further reading attached, to boot. ☺ – JdeBP Dec 22 '15 at 18:24
  • 3
    @JulesMazur ...the answers so far are fairly subjective... A "subjective" statement is essentially opinion-based by definition. /bin/bash should only be used when bash is explicitly needed. In 40+ years as a developer, long before bash, I almost never explicitly needed it except when testing. (I also strive to avoid shell extensions, but most of my scripts are intended for distribution.) Many scripts on the net should also be intended for wide use. – user2338816 Dec 23 '15 at 5:18
  • 2
    @user2338816 my bad, I meant objective. Thanks for your points! – Jules Dec 23 '15 at 5:36
84
  1. There are systems not shipping bash by default (e.g. FreeBSD).
  2. Even if bash is installed, it might not be located in /bin.
  3. Most simple scripts don't require bash.
  4. Using the POSIX shell is more portable and the scripts will run on a greater variety of systems.
  • 17
    Another reason: often /bin/sh is faster than bash, or at least loads quicker (due to being smaller). – derobert Dec 22 '15 at 15:11
  • 5
    @derobert, /bin/sh is faster if it's not bash, there still are a few systems like OS/X or RHEL where /bin/sh is bash. – Stéphane Chazelas Dec 22 '15 at 15:36
  • 1
    No. Some OS link it, because bash is backwards compatible. – Sobrique Dec 22 '15 at 16:09
  • 7
    Quite a few scripts assume that /bin/sh is /bin/bash. Ubuntu switching from bash to dash broke all of them. – atamanroman Dec 22 '15 at 18:58
  • 19
    @atamanroman: The scripts were incorrect in the first place, they should have used #!/bin/bash if they wanted Bash (nothing wrong with that!). The change was mostly done upstream in Debian. It improved user experience, it had a measurable impact on system startup time. It also positively impacted security, see "Shellshock". – Dietrich Epp Dec 22 '15 at 23:28
28

Most system scripts in (Debian related: Ubuntu, Mint, etc.) Linux are written to run in the faster dash, which is the default /bin/sh in those systems. The reason is twofold:

  • Speed of the system. A smaller code of dash loads faster and also run faster. With some (small?) additional effort (cost) to programmers of shell scripts.

  • Security. Having diversity of shells helps resilience to bugs. Debian systems were mostly not vulnerable to shellshock because the default shell did not have such vulnerability.

Bash is indeed the default shell for users, as is more powerful and has much more elements to make coding easier. It is also the default sh in Mac OS (the one linked from /bin/sh). However, calling bash with the link name of sh makes it start as a posix compliant shell.

  • 2
    A more limited set of available tools of a simpler shell makes writing code for it more difficult (please avoid any fanatic war on this). That is why some users like zsh, which has even more tools available than bash. I like Bash more as is a balance between both extremes. – user79743 Dec 22 '15 at 16:24
  • 4
    @RobertL, many of the facilities added in ksh and adopted by bash exist because they substantially ease the process of writing robust and correct scripts. Without the various additions allowing indirect assignment and evaluation to be performed safely, for instance, one can find oneself using eval, with attendant security exposure; similarly, without built-in regex support, one can need to use external commands (at a heavy performance penalty) for matching even within a single line, etc. – Charles Duffy Dec 22 '15 at 18:30
  • 1
    @RuiFRibeiro, nothing is statically linked in Debian. Dash is more limited, but it is limited mainly in interactive features (no completion and such) so that it is faster for scripts. – Jan Hudec Dec 23 '15 at 11:31
21

Others have pointed out that the premises of the question, that the Bourne Again shell is default and ubiquitous, are downright wrong.

In addition to that, there are indeed good reasons for using something other than the Bourne Again shell for interpreting shell scripts. These reasons motivated Ubuntu's and Debian's big project, over a number of years, to remove bashisms and to make as many of the shell scripts run by system initialization (which was a lot of shell scripts with System 5 rc) and package installation/removal use the Debian Almquist shell instead of the Bourne Again shell.

Simply put: The Bourne Again shell, chock full of interactive features as it is, is not the fastest shell interpreter for a POSIX-conformant shell script. So if one can make one's shell scripts POSIX-conformant, interpreting them with a more lightweight program, like the Debian Almquist shell, one's system will perform better. (In the end, Debian had to make slight adjustments to the Almquist shell, to add support for a couple of non-POSIX shell constructs that were simply too deeply and widely embedded and too useful to get rid of.)

The result of it all was a major gain in bootstrap performance.

So there are two distinct classes of shell to consider, here:

  • The shells with all of the flashy interactive features, which are configured as the interactive login shells for users in the accounts database.
  • The shells that interpret lots of scripts quickly, which are used as the script interpreters by shell script programs.

Note that talking about this as "preferring /bin/sh" is oversimplifying. Debian actually had at least two goals:

  1. In the face of administrators using the Debian Almquist shell, the Z Shell (in POSIX mode), the Bourne Again shell (in POSIX mode), the MirBSD Korn shell, and others as /bin/sh, there was either …

    1. … making the scripts as portable as possible, so that switching what /bin/sh mapped to didn't break things; or

    2. … making non-portable scripts explicitly target the correct interpreter program, instead of simply expecting that /bin/sh map to it.

  2. There was making the Debian Almquist shell the default mapping for /bin/sh instead of the Bourne Shell, so that those scripts that were POSIX-conformant (or, more properly, Debian Policy Manual conformant) ran more quickly.

And of course once one gets into this, one can take it a lot further; such as considering the efficiency tradeoffs of the likes of /bin/true and /usr/bin/clear being shell scripts or compiled programs. But that's beyond the scope of this answer, fortunately. ☺

None of this is very new, nor even Unix-specific, of course. Back before the turn of the century, I wrote and published a command-line interpreter that came in both "interactive" and "non-interactive" flavours, explaining this very division in its doco and noting the difference between the COMSPEC and OS2_SHELL environment variables. Similarly, discussion of removing bashisms in Debian's System V rc and package installation/removal scripts dates back to the 1990s.

Further reading

  • 2
    "In the end, Debian had to make slight adjustments to the Almquist shell, to add support for a couple of non-POSIX shell constructs that were simply too deeply and widely embedded and too useful to get rid of." — Which of your many links has info about this? That sounds very interesting. :) – Wildcard Dec 23 '15 at 2:57
  • 3
    IMHO, performance is only a motivator to get people to agree with the changes. The initial big reason for changing was that bash kept breaking backwards compatibility. I've personally had to fix bash problems at least 3 times in my career because the script would work in one version of bash but failed in another (usually happens after OS upgrade). Dash is not merely a slightly faster interpreter. It is also much more stable in terms of behaviour. – slebetman Dec 23 '15 at 9:12
  • I would be interested whether the comments in the Schily Bourne Shell man page, see schilytools.sourceforge.net/bosh.html are suitable to permit people to understand how to write a portable script (that only depends on Bourne Shell features from 1989). What I did was mentioning every enhancement that was not in old Bourne Shells. BTW: I am also interested to know a list of bashisms in dash. – schily Dec 23 '15 at 9:59
8

Is there any reason to have a shebang pointing at /bin/sh rather than /bin/bash?

Yes. @Marco's excellent answer outlines this well.

What should I use in my shebang?

When writing your own scripts, you should point the shebang to the most general thing that you have tested against.

On my system (Centos 6.6), sh is symlinked to bash:

$ ls -l /bin/sh 
lrwxrwxrwx 1 root root 4 Dec  2  2014 /bin/sh -> bash

This means that I always use #!/bin/bash in my shebang unless I have verified that I don't have bashims in my script.

By setting the shebang to #!/bin/sh you are promising that the script will work with all implementations of sh.

This is a much bigger promise than saying the script will work with bash.

Here is an example of a script that will behave incorrectly depending on what sh implementation the system is using:

#!/bin/sh
n=1
a=$((++n))
echo $n

When using bash the script will print:

2

When using dash the script will print:

1

If I want to use #!/bin/sh what do I need to do?

  • Check the script with checkbashisms - Note that this will not find all bashims. It didn't find the bashism in my script above
  • Test the script using another sh implementation. I typically test with dash, however I expect that some bashisms or dashims can still slip through.

The DashAsBinSh page on the Ubuntu wiki has lots of interesting info.

  • 6
    "When writing your own scripts, you should point the shebang to the most general thing that you have tested against....By setting the shebang to #!/bin/sh you are promising that the script will work with all implementations of sh." Excellent point. +1, and you have made me rethink how I will write my shebangs for the future. Thank you! :) – Wildcard Dec 23 '15 at 3:08
  • 2
    Well, not all implementations of /bin/sh; just the POSIX-compliant ones. – Blacklight Shining Dec 23 '15 at 9:00
4

The only remaining reason to write a shell script, instead of a script in a more powerful and ergonomic language, is if portability to legacy systems with an unknown set of installed software is more important than any other factor.

/bin/sh is the one and only script interpreter that's available on everything that calls itself Unix. But on an awful lot of legacy systems, /bin/sh and the associated utilities are not even compliant with the POSIX.1-1996 "shell and utilities" spec, let alone anything more modern. Standard-compliant tools are an optional add-on, installed in /usr/xpg4 or some such non-obvious location.1 Scripting to the portable-subset shell language is even more tedious and error-prone than scripting to the POSIX shell language. (Read through an Autoconf-generated configure script sometime if you don't believe me. Just the setup should be enough to convince you.)

But if you can assume any other script interpreter is installed (e.g. Bash) then you can assume an interpreter for a better scripting language is installed. Perl, for instance, is more likely to be available than Bash is.

Therefore, you should never write a #! /bin/bash script, because if that's an option, a better language is also an option.

1 For instance, Solaris 10 and older shipped the original Bourne shell as /bin/sh. I am informed that Solaris 11 updated it to ksh93.

  • 3
    In which language will you write an script to boot a system? Or inside a SOHO router (limited embebed systems)? Or in Android? A shell will be available in all those cases. Perl not. – user79743 Dec 22 '15 at 16:43
  • 1
    There are some inaccuracies about the Solaris related parts of your answer. On Solaris 10 and older, /bin/sh is not POSIX.1-1996 but actually a pre-POSIX syntax original Bourne shell. That makes #!/bin/sh a very poor shebang for scripts to run with these releases. Portable scripts on Solaris would use #!/usr/xpg4/bin/sh which won't be very portable on other OSes. On the latest Solaris, Oracle Solaris 11 first released 2011, /bin/sh is a modern ksh93 that complies with recent POSIX specs, and has many modern extensions. – jlliagre Dec 22 '15 at 16:53
  • 1
    @BinaryZebra: "A shell" will be available, yes. But bash is not necessarily that shell (in particular most SOHO routers use ash which is provided with busybox), and I tend to think zwol is right that perl is more commonly available than bash. – Ben Voigt Dec 22 '15 at 16:53
  • 1
    @BenVoigt I am commenting on this sentence "The only remaining reason to write a shell script". There are still some instances that need a shell for some tasks (not all). Those were some instances from the top of my head. OTOH In systems with enough memory (almost all in today standards) and enough power installing Perl (or Python, or ....) is quite quick and easy. However, I am not advocating for any specific shell. Where do you read that in my comment? – user79743 Dec 22 '15 at 17:01
  • 2
    Disagree utterly with your highly opinionated and nonfactual claim that "if bash is available then so is a better language so you should never write any bash code." Also, as @sixtyfootersdude points out, you should always use #!/bin/bash unless you have tested that your script works with any POSIX shell. – Wildcard Dec 23 '15 at 2:55
0

You should actually be using either

#! /bin/env sh

or

#! /bin/env bash

that way you invoke either shell by the way they're install on that system.

To be super safe (eg in cases of single-user reboots) use sh otherwise use bash.

  • 6
    From this answer: the advantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH. The disadvantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH. This probably also applies to sh and bash. – Jules Dec 23 '15 at 5:12
  • 12
    No, you should not use #!/bin/env anything in a portable script. It is perfectly reasonable to assume that /bin/sh exists and is a working, POSIX-compliant shell. On the other hand, none of my systems have a /bin/env. – Blacklight Shining Dec 23 '15 at 9:04
  • Also a good point. – Jules Dec 23 '15 at 14:54
  • 1
    @Blacklight Shining it is definitely wrong to assume a POSIX compliant shell in /bin/sh. POSIX does not require it and rather defines other rules to get a POSIX compliant environment on a POSIX certified platform. – schily Dec 23 '15 at 18:17
  • 4
    /usr/bin/env isn't universally available... – vonbrand Dec 27 '15 at 22:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.