Why does /bin/sh behave differently to /bin/bash even if one points to the other?

LinuxBashShellSh

Linux Problem Overview


While I was playing around in my shell investigating the answer to this question, I noticed that, even though /bin/sh was pointing to /bin/bash on my system, the two commands behave differently. First of all, the output of

ls -lh /bin/sh

is:

lrwxrwxrwx 1 root root 4 Apr 22  2013 /bin/sh -> bash*

However, invoking the following command through /bin/sh:

/bin/sh -c "script.sh 2> >( grep -v FILTER 2>&1 )"

returns this error:

/bin/sh: -c: line 0: syntax error near unexpected token '>'
/bin/sh: -c: line 0: 'script.sh 2> >( grep -v FILTER 2>&1 )'

While running the same command through /bin/bash:

/bin/bash -c "script.sh 2> >( grep -v FILTER 2>&1 )"

executes successfully, here is the output:

This should be on stderr

For reference, here is the contents of script.sh:

#!/bin/sh
echo "FILTER: This should be filtered out" 1>&2
echo "This should be on stderr" 1>&2
echo "FILTER: This should be filtered out" 1>&2

Why do the two invocations behave differently?

Linux Solutions


Solution 1 - Linux

bash looks at the value of $argv[0] (bash is implemented in C) to determine how it was invoked.

Its behavior when invoked as sh is documented in the manual:

> If Bash is invoked with the name sh, it tries to mimic the startup > behavior of historical versions of sh as closely as possible, while > conforming to the POSIX standard as well. > > When invoked as an interactive login shell, or as a non-interactive > shell with the -login option, it first attempts to read and execute > commands from /etc/profile and ~/.profile, in that order. The > --noprofile option may be used to inhibit this behavior. When invoked as an interactive shell with the name sh, Bash looks for the variable > ENV, expands its value if it is defined, and uses the expanded value > as the name of a file to read and execute. Since a shell invoked as sh > does not attempt to read and execute commands from any other startup > files, the --rcfile option has no effect. A non-interactive shell > invoked with the name sh does not attempt to read any other startup > files. > > When invoked as sh, Bash enters POSIX mode after the startup files are > read

There's a long list (currently 46 items) of things that change when bash is in POSIX mode, documented here.

(POSIX mode is probably useful mostly as a way to test scripts for portability to non-bash shells.)

Incidentally, programs that change their behavior depending on the name under which they were invoked are fairly common. Some versions of grep, fgrep, and egrep are implemented as a single executable (though GNU grep doesn't do this). view is typically a symbolic link to vi or vim; invoking it as view causes to open in read-only mode. The Busybox system includes a number of individual commands that are all symlinks to the master busybox executable.

Solution 2 - Linux

Invoking bash as sh causes it to enter posix mode after reading the startup files it would normally read (as opposed to the startup files a POSIX sh would read.) Bash has many different invocation modes. You can find out about these modes from the INVOCATION section of the manual. Here is some detail about the POSIX mode.

POSIX mode

This mode means bash will try, in various degrees, to conform to POSIX expectations. As explained here, bash has a few different invocations for this mode, with slightly different implications:

  1. sh: Bash enters POSIX mode after reading startup files.
  2. bash --posix: Bash enters POSIX mode before reading startup files.
  3. set -o posix: Bash switches to POSIX mode.
  4. POSIXLY_CORRECT: If this variable is in the environment when bash starts, the shell enters posix mode before reading the startup files, like bash --posix. If it is set while bash is running, like set -o posix.

Solution 3 - Linux

From the Bash Reference Manual:

> If Bash is invoked with the name sh, it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.

Solution 4 - Linux

Because the bash binary checks how it was invoked (via argv[0]) and enters a compatibility mode if it's being run as sh.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSquirrelView Question on Stackoverflow
Solution 1 - LinuxKeith ThompsonView Answer on Stackoverflow
Solution 2 - LinuxkojiroView Answer on Stackoverflow
Solution 3 - LinuxEtan ReisnerView Answer on Stackoverflow
Solution 4 - LinuxCarl NorumView Answer on Stackoverflow