Difference between sh and Bash
Solution 1
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:
- Modern Debian and Ubuntu systems, which symlink
sh
todash
by default; -
Busybox, which is usually run during the Linux system boot time as part of
initramfs
. It uses the ash shell implementation. -
BSD systems, and in general any non-Linux systems. OpenBSD uses
pdksh
, a descendant of the KornShell. FreeBSD'ssh
is a descendant of the original Unix Bourne shell. Solaris has its ownsh
which for a long time was not POSIX-compliant; a free implementation is available from the Heirloom project.
How can you find out what /bin/sh
points to on your system?
The complication is that /bin/sh
could be a symbolic link or a hard link. If it's a symbolic link, a portable way to resolve it is:
% file -h /bin/sh
/bin/sh: symbolic link to bash
If it's a hard link, try
% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash
In fact, the -L
flag covers both symlinks and hardlinks,
but the disadvantage of this method is that it is not portable —
POSIX does not require find
to support the -samefile
option, although both GNU find and FreeBSD find support it.
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
For my own scripts, I prefer sh
for the following reasons:
- it is standardized
- it is much simpler and easier to learn
- it is portable across POSIX systems — even if they happen not to have
bash
, they are required to havesh
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.
Solution 2
sh
: http://man.cx/sh
Bash: http://man.cx/bash
TL;DR: Bash is a superset of sh
with a more elegant syntax and more functionality. It is safe to use a Bash shebang line in almost all cases as it's quite ubiquitous on modern platforms.
NB: in some environments, sh
is Bash. Check sh --version
.
Solution 3
This question has frequently been nominated as a canonical for people who try to use sh
and are surprised that it's not behaving the same as bash
. Here's a quick rundown of common misunderstandings and pitfalls.
First off, you should understand what to expect.
- If you run your script with
sh scriptname
, or run it withscriptname
and have#!/bin/sh
in the shebang line, you should expect POSIXsh
behavior. - If you run your script with
bash scriptname
, or run it withscriptname
and have#!/bin/bash
(or the local equivalent) in the shebang line, you should expect Bash behavior.
Having a correct shebang and running the script by typing just the script name (possibly with a relative or full path) is generally the preferred solution. In addition to a correct shebang, this requires the script file to have execute permission (chmod a+x scriptname
).
So, how do they actually differ?
The Bash Reference manual has a section which attempts to enumerate the differences but some common sources of confusion include
-
[[
is not available insh
(only[
which is more clunky and limited). See also Difference between single and double square brackets in Bash -
sh
does not have arrays. - Some Bash keywords like
local
,source
,function
,shopt
,let
,declare
, andselect
are not portable tosh
. (Somesh
implementations support e.g.local
.) - Bash has many C-style syntax extensions like the three-argument
for((i=0;i<=3;i++))
loop,+=
increment assignment, etc. The$'string\nwith\tC\aescapes'
feature is tentatively accepted for POSIX (meaning it works in Bash now, but will not yet be supported bysh
on systems which only adhere to the current POSIX specification, and likely will not for some time to come). - Bash supports
<<<'here strings'
. - Bash has
*.{png,jpg}
and{0..12}
brace expansion. - Bash has extended globbing facilities like
**
(globstar
) for recursing subdirectories, andextglob
for using a different, more versatile wildcard syntax. -
This is in POSIX, but may be missing from some pre-POSIX~
refers to$HOME
only in Bash (and more generally~username
to the home directory ofusername
)./bin/sh
implementations. - Bash has process substitution with
<(cmd)
and>(cmd)
. - Bash has Csh-style convenience redirection aliases like
&|
for2>&1 |
and&>
for> ... 2>&1
- Bash supports coprocesses with
<>
redirection. - Bash features a rich set of expanded non-standard parameter expansions such as
${substring:1:2}
,${variable/pattern/replacement}
, case conversion, etc. - Bash has significantly extended facilities for shell arithmetic (though still no floating-point support). There is an obsolescent legacy
$[expression]
syntax which however should be replaced with POSIX arithmetic$((expression))
syntax. (Some legacy pre-POSIXsh
implementations may not support that, though.) - Several built-in commands have options which are not portable, like
type -a
,printf -v
, and the perennialecho -e
. - Magic variables like
$RANDOM
,$SECONDS
,$PIPESTATUS[@]
and$FUNCNAME
are Bash extensions. - Syntactic differences like
export variable=value
and[ "x" == "y" ]
which are not portable (portable string comparison inexport variable
should be separate from variable assignment, and[ ... ]
uses a single equals sign). - Many, many Bash-only extensions to enable or disable optional behavior and expose internal state of the shell.
- Many, many convenience features for interactive use which however do not affect script behavior.
Remember, this is an abridged listing. Refer to the reference manual for the full scoop, and http://mywiki.wooledge.org/Bashism for many good workarounds; and/or try http://shellcheck.net/ which warns for many Bash-only features.
A common error is to have a #!/bin/bash
shebang line, but then nevertheless using sh scriptname
to actually run the script. This basically disables any Bash-only functionality, so you get syntax errors e.g. for trying to use arrays. (The shebang line is syntactically a comment, so it is simply ignored in this scenario.)
Unfortunately, Bash will not warn when you try to use these constructs when it is invoked as sh
. It doesn't completely disable all Bash-only functionality, either, so running Bash by invoking it as sh
is not a good way to check if your script is properly portable to ash
/dash
/POSIX sh
or variants like Heirloom sh
.
If you want to check for strict POSIX compliance, try posh
in its designated POSIX mode
(which however does not seem to be properly documented).
As an aside, the POSIX standardization effort is intended to specify the behavior of various U*x-like platform behaviors, including the shell (sh
).
However, this is an evolving document, and so, some implementations adhere to an earlier version of the POSIX specification; furthermore, there are some legacy implementations which didn't even try to adhere to POSIX.
Solution 4
Shell is an interface between a user and OS to access to an operating system's services. It can be either GUI or CLI (Command Line interface).
sh (Bourne shell) is a shell command-line interpreter, for Unix/Unix-like operating systems. It provides some built-in commands. In scripting language we denote interpreter as #!/bin/sh
. It was one most widely supported by other shells like bash (free/open), kash (not free).
Bash (Bourne again shell) is a shell replacement for the Bourne shell. Bash is superset of sh. Bash supports sh. POSIX is a set of standards defining how POSIX-compliant systems should work. Bash is not actually a POSIX compliant shell. In a scripting language we denote the interpreter as #!/bin/bash
.
Analogy:
- Shell is like an interface or specifications or API.
- sh is a class which implements the Shell interface.
- Bash is a subclass of the sh.
Solution 5
Post from UNIX.COM
Shell features
This table below lists most features that I think would make you choose one shell over another. It is not intended to be a definitive list and does not include every single possible feature for every single possible shell. A feature is only considered to be in a shell if in the version that comes with the operating system, or if it is available as compiled directly from the standard distribution. In particular the C shell specified below is that available on SUNOS 4.*, a considerable number of vendors now ship either tcsh or their own enhanced C shell instead (they don't always make it obvious that they are shipping tcsh.
Code:
sh csh ksh bash tcsh zsh rc es
Job control N Y Y Y Y Y N N
Aliases N Y Y Y Y Y N N
Shell functions Y(1) N Y Y N Y Y Y
"Sensible" Input/Output redirection Y N Y Y N Y Y Y
Directory stack N Y Y Y Y Y F F
Command history N Y Y Y Y Y L L
Command line editing N N Y Y Y Y L L
Vi Command line editing N N Y Y Y(3) Y L L
Emacs Command line editing N N Y Y Y Y L L
Rebindable Command line editing N N N Y Y Y L L
User name look up N Y Y Y Y Y L L
Login/Logout watching N N N N Y Y F F
Filename completion N Y(1) Y Y Y Y L L
Username completion N Y(2) Y Y Y Y L L
Hostname completion N Y(2) Y Y Y Y L L
History completion N N N Y Y Y L L
Fully programmable Completion N N N N Y Y N N
Mh Mailbox completion N N N N(4) N(6) N(6) N N
Co Processes N N Y N N Y N N
Builtin artithmetic evaluation N Y Y Y Y Y N N
Can follow symbolic links invisibly N N Y Y Y Y N N
Periodic command execution N N N N Y Y N N
Custom Prompt (easily) N N Y Y Y Y Y Y
Sun Keyboard Hack N N N N N Y N N
Spelling Correction N N N N Y Y N N
Process Substitution N N N Y(2) N Y Y Y
Underlying Syntax sh csh sh sh csh sh rc rc
Freely Available N N N(5) Y Y Y Y Y
Checks Mailbox N Y Y Y Y Y F F
Tty Sanity Checking N N N N Y Y N N
Can cope with large argument lists Y N Y Y Y Y Y Y
Has non-interactive startup file N Y Y(7) Y(7) Y Y N N
Has non-login startup file N Y Y(7) Y Y Y N N
Can avoid user startup files N Y N Y N Y Y Y
Can specify startup file N N Y Y N N N N
Low level command redefinition N N N N N N N Y
Has anonymous functions N N N N N N Y Y
List Variables N Y Y N Y Y Y Y
Full signal trap handling Y N Y Y N Y Y Y
File no clobber ability N Y Y Y Y Y N F
Local variables N N Y Y N Y Y Y
Lexically scoped variables N N N N N N N Y
Exceptions N N N N N N N Y
Key to the table above.
Y Feature can be done using this shell.
N Feature is not present in the shell.
F Feature can only be done by using the shells function mechanism.
L The readline library must be linked into the shell to enable this Feature.
Notes to the table above
- This feature was not in the original version, but has since become almost standard.
- This feature is fairly new and so is often not found on many versions of the shell, it is gradually making its way into standard distribution.
- The Vi emulation of this shell is thought by many to be incomplete.
- This feature is not standard but unofficial patches exist to perform this.
- A version called 'pdksh' is freely available, but does not have the full functionality of the AT&T version.
- This can be done via the shells programmable completion mechanism.
- Only by specifying a file via the ENV environment variable.
![Weiwei Yang](https://i.stack.imgur.com/BubMO.jpg?s=256&g=1)
Weiwei Yang
Updated on April 15, 2022Comments
-
Weiwei Yang about 2 years
When writing shell programs, we often use
/bin/sh
and/bin/bash
. I usually usebash
, but I don't know what's the difference between them.What's main difference between Bash and
sh
?What do we need to be aware of when programming in Bash and
sh
?-
StackExchange saddens dancek about 13 yearsFor a useful list of bashisms and corresponding code that works on Bourne shell, see mywiki.wooledge.org/Bashism
-
Maurício C Antunes almost 11 yearsYou may want to see the POSIX standard for sh and its command language: * sh * Shell Command Language
-
osirisgothra over 10 yearsas a general rule, all sh scripts will run under bash thanks to it's posix compatibility, but not all bash scripts can run under sh, the main differences you notice are things like [[ ]] instead of [ ] comparisons which allow unquoted spaces, $(( )) instead of $[ ] arithmetic expressions, and other things like "its too big and too slow" directly from the bash docs.. But new scripters need not limit themselves to sh-compatible scripts unless they are shooting for some backward compatibility, which more often than not is not the case these days, after all it is (or was...) the year 2014 right??
-
-
glenn jackman about 13 yearsif bash is invoked as sh, it behaves a bit differently. See gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files ("Invoked with name sh") and gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode. For example, no process substitution.
-
user674062 about 13 yearsAs bash is a superset of sh and some OS like FreeBSD do not have bash installed by default, scripting in sh will give greater portability.
-
schily almost 9 yearsYour table is not useful to me as it tries to compare features of the Bourne Shell and features from ksh from before 1988. If you really make a table for 1988, you would need to remove most of the other shells from that table - including bash, sh and rc. Could you explain where did yo get the values for your table from?
-
schily almost 9 yearsLet me give some hints: Job Control was added to the Bourne Shell in 1989 and the Bourne Shell was made OpenSource in 2005. The Korn shell has process substitution since at least 1988 and it is OpenSource since 1997. BTW: your statements regarding $ENV are not correct, $ENV is only read/executed for interactive shells.
-
schily almost 9 yearsAs there is no portable scriptable way to get a POSIX shell for a specific script, portable scripts cannot assume more than Bourne Shell features.
-
schily almost 9 years
sh
only gives you a POSIX shell, if you have the rightPATH
set up in your current shell. There is no defined PATH-name that gives you a POSIX shell. -
SriniV almost 9 years@schily This post has been captured from cs.virginia.edu/helpnet/Computer_OS/unix/shells/shelldiff.html
-
SriniV almost 9 years@schily If you feel it is incorrect anywhere, please feel free to edit it appropriately.
-
schily almost 9 yearsThank you for the pointer! The problem with the table is that it is biased, because it has notice (1) at all but does not use it e.g. for bash. I am sure that we would need to use it for many features of bash but it is not possible anymore to find a reliable source for such a change. Note that the oldest Bourne Shell source is still available, but the oldest bash source I am able to find is for bash-1.14.7 from 1996 Another problem is that the table contains many lines that refer to features I cannot associate with a property, e.g.
Mh Mailbox completion
orSun keyboard hack
. -
schily almost 9 yearsSo how to deal with such "features"? Also note that shortly after the Bourne Shell was made OpenSource, I started to enhance the Bourne Shell and since 2006, there is e.g. a version with the history editor I designed/prototyped in 1982 and implemented in 1984 for my "bsh" (not Bourne Shell related). BTW: David Korn also started with the Bourne Shell source around 198/1984.
-
danno over 8 yearsBased on what schily exposed it would seem that it would be better to remove this answer, as it is essentially fraudulent, and OP didn't really vet the information he pasted.
-
tripleee about 8 yearsFor a long time,
sh
was not necessarily even giving you a POSIX shell, on Solaris, for example. -
Cees Timmerman over 7 years
-
tripleee over 7 yearsserverfault.com/a/98772/98333 highlights some of the issues with
zsh
. Bash at least tries to be POSIX if you ask nicely. -
tripleee over 7 yearsThis is basically what my answer as of just now really boils down to. +1
-
tripleee over 7 yearsFundamentally, the TL;DR ersion is And's answer.
-
Keerthana Prabhakaran about 6 yearsI don't get it. You've mentioned both "Bash is superset of sh" and "Bash is a subclass of the sh", aren't they contrary statements? Can you please clarify?
-
tripleee about 6 yearsI think this is trying to say Bash inherits from
sh
(so it's a "subclass" in the OOP sense) and extends it (so has a superset of the functionality). -
vhs almost 6 yearsshellcheck.net was all I needed. many thanks.
-
tripleee over 4 years
sh
far predates POSIX. These days, you would hope that anysh
you find is at least POSIX-compatible; but on legacy systems this is by no means a given. POSIX stadardizes far more than the shell; in fact, you could argue that the standardization of operating system calls and library functions is more important. -
tripleee over 4 yearsThere was an earlier shell by Ken Thompson. The Bourne shell was officially introduced in v7 Unix (1979).
-
Ryan Taylor over 4 yearsI removed the stuff about POSIX to make it less confusing
-
Handsome Nerd about 4 yearsIf you run a script with
bash
the display way more useful error messages in the case of syntax error. You can simply save time by using bash. -
joharr about 4 yearsWhat does the
%
mean at the beginning of your command lines? -
Raihanhbh about 4 yearsTo understand POSIX, read the response from Alex Please check: stackoverflow.com/a/1780614/1261003
-
Scratte about 4 yearsI'm not trying to understand POSIX. I'm reviewing your Answer and as such I need to see it your Answer adds value. I do not think it does.
-
Raihanhbh about 4 yearsI believe these small clarifications would help a novice to understand the jargon used in the above discussions more comfortably. @Scratte
-
Roman Cheplyaka about 4 years@JosephHarriott it's a prompt: a character printed by the shell itself after which your command follows. Some shells use
$
instead of%
, or#
for the root shell. -
Roman Cheplyaka about 4 yearsFWIW,
export variable=value
is mandated by POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/export.html. Perhaps it's not available in some ancient shells, but it's definitely not a bashism. -
joharr about 4 years@RomanCheplyaka which shells ? I've only ever seen
$
and#
... -
raminr about 4 years@RomanCheplyaka I am certain
sh
existed well before bash (which stands for bourne-again shell). But it was very primitive and didn't respond to terminal events, likeESC
characters. Thenksh
came (also before bash), then bash started by those who loved the idea of a better shell, but hated ksh. :-) -
RichieD almost 4 years@JosephHarriott -
%
is commonly the prompt for user shells of the C Shell variety (e.g. csh, tcsh).#
has been traditionally reserved as the prompt character for superuser (root) shells, regardless of which one is chosen. But that's all in the realm of common / typical usage, as historically / traditionally observed. You can use what you like and/or what your users will tolerate. :) Google on how -
Yohanim almost 4 yearswhere is tldr;?
-
jcarlosweb over 3 yearsYou say you prefer
sh
. What is the documentation for sh? Everything I find is with BASH? So what a mess. Also, what is the problem if in a script that I have bash#!/bin/bash
I dosh script_with_bash.sh
, I see the same thing happens. -
Adrian about 3 yearsShell is not the same with sh?
-
tripleee almost 3 yearsThe default prompt in Zsh is also
%
, even though traditionally that was used to signify a Csh-family shell. This is by no means the only area where Zsh deviates from tradition. -
tripleee almost 3 years
sh
programs should run fine in Bash in practice, not just "in theory". There are obviously corner cases like when a script uses a variable whose name is reserved by Bash but not by other shells. -
Roberto over 2 yearsIt would be nice if you could add info about macOS in your answer too. Btw, why do we have to point to the current directory
./
to run a script when you are already there? -
tripleee over 2 yearsThe screen shot is weird; where does it come from? If the "underlying syntax" for Bash is
sh
, then that should be listed as the underying syntax forksh
too. Conversely, you could argue that the underlying syntax for Bash isksh
, as Bash has borrowed quite liberally from the Korn shell over the years. -
F. Hauri - Give Up GitHub about 2 yearsI didn't know Heirloom sh, but seem not still active... I often use
busybox sh
when working in rescue mode...