#!/bin/bash more appropriate than
#!/bin/sh in a shell script?
There are several shells which implement a superset of the POSIX sh specification. On different systems,
/bin/shmight be a link to ash, bash, dash, ksh, zsh, &c. (It will always be sh-compatible though – never csh or fish.)
As long as you stick to
shfeatures only, you can (and probably even should) use
#!/bin/shand the script should work fine, no matter which shell it is.
If you start using bash-specific features (e.g. arrays), you should specifically request bash – because, even if
/bin/shalready invokes bash on your system, it might not on everyone else's system, and your script will not run there. (The same of course applies to zsh and ksh.) You can use shellcheck to identify bashisms.
Even if the script is for personal use only, you might notice that some OSes change
/bin/shduring upgrades – e.g. on Debian it used to be bash, but later was replaced with very minimal dash. Scripts which used bashisms but had
#!/bin/bashis not very correct. On different systems, bash might live in
A more reliable option is
#!/usr/bin/env bash, which uses $PATH. (Although the
envtool itself isn't strictly guaranteed either,
/usr/bin/envstill works on more systems than
Use the shebang corresponding to the shell you actually used to develop and debug your script. I.e. if your login shell is
bash, and you run your script as executable in your terminal, use
#!/bin/bash. Don't just assume that since you haven't used arrays (or whatever
bash feature you're aware of), you're safe to pick whatever shell you like. There are many subtle differences between shells (
echo, functions, loops, you name it) which cannot be discovered without proper testing.
Consider this: if you leave
#!/bin/bash and your users don't have it, they will see a clear error message, something like
Error: /bin/bash not found
Most users can fix this under one minute by installing the appropriate package. On the other hand, if you replace the shebang by
#!/bin/sh and test it on a system where
/bin/sh is a symlink to
/bin/bash, your users which don't have
bash will be in trouble. They'll most likely see a cryptic error message like:
Error in script.sh line 123: error parsing token xyz
This may take hours to fix, and there will be no clue about which shell they should have used.
There aren't many reasons why you'd want to use a different shell in the shebang. One reason is when the shell you have used is not widespread. Another one is to gain performance with
sh which is significantly faster on some systems, AND your script will be a performance bottleneck. In that case, test your script thoroughly with the target shell, then change the shebang.
You should only ever use
You should not use bash (or zsh, or fish, or ...) extensions in a shell script, ever.
You should only ever write shell scripts that work with any implementation of the shell language (including all the "utility" programs that go along with the shell itself). These days you can probably take POSIX.1-2001 (not -2008) as authoritative for what the shell and utilities are capable of, but be aware that you may one day be called upon to port your script to a legacy system (e.g. Solaris or AIX) whose shell and utilities were frozen circa 1992.
Here's the thing: Shell is a terrible programming language. The only thing it has going for it is that
/bin/sh is the one and only script interpreter that every Unix installation is guaranteed to have.
Here's the other thing: some iteration of the core Perl 5 interpreter (
/usr/bin/perl) is more likely to be available on a randomly selected Unix installation than
(/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash is. Other good scripting languages (Python, Ruby, node.js, etc. — I'll even include PHP and Tcl in that category when comparing to shell) are also roughly as available as bash and other extended shells.
Therefore, if you have the option of writing a bash script, you have the option of using a programming language that isn't terrible, instead.
Now, simple shell scripts, the kind that just run a few programs in a sequence from a cron job or something, there's nothing wrong with leaving them as shell scripts. But simple shell scripts don't need arrays or functions or
[[ even. And you should only write complicated shell scripts when you don't have any other choice. Autoconf scripts, for instance, are properly still shell scripts. But those scripts have to run on every incarnation of
/bin/sh that's relevant to the program being configured. and that means they cannot use any extensions. You probably don't have to care about old proprietary Unixes these days, but you probably should care about current open-source BSDs, some of which don't install
bash by default, and embedded environments that give you only a minimal shell and
In conclusion, the moment you find yourself wanting a feature that's not available in the portable shell language, that is a sign that the script has become too complicated to stay a shell script. Rewrite it in a better language instead.
Generally if time is more important than functionality you will use the faster shell. sh is often aliased to dash and tends to be used for root's cron tasks or batch operations where every (nano) second counts.
To be even more brief, use
sh if portability across the most systems is most important and
bash if you'd like to use some of its specific features, such as arrays, if the version of bash supports it.
- sh (for most cases), bash if specifically required (or ksh, or whatever)
The safest path. when hard coded, would be /usr/bin/
shellOfChoice but a new convention I am trying to use always now - as 'default locations' via a change PATH may change is:
or for e.g., perl scripts
#!/usr/bin/env perl -w
Of course, when you have a reason for a script to NEVER be automatically taking a new PATH then continue to have it hard-coded - and then /usr/bin/something should be the most likely path to use.