tags:

views:

59

answers:

2

I have noticed that Solaris 10's Bourne shell, /bin/sh (and also /sbin/sh) forks a subshell when using indirection (<). I have tried a pile of other Bourne-ish shells, including:

  • The POSIX /usr/xpg4/bin/sh shell on Solaris 10
  • /bin/bash, /bin/ksh on Solaris 10
  • /bin/sh on AIX 5
  • /bin/sh on Debian Linux 5

and none of these exhibit this behavior.

I'm amazed I haven't been bitten by this before. For example, in the saner shells (ie all those listed above) the following script outputs "1":

$ cat foo
#!/bin/sh
x=0
while read y ; do
  x=1
done </etc/passwd
echo $x
$ ./foo
0
$

Solaris 10's /bin/sh returns 0 because the assignment x=1 occurs in the subshell caused by the indirection: when the subshell exits that assignment is lost. (If I remove </etc/passwd and read from stdin instead then "1" is output, as expected).

Is there some age-old reason that the "traditional" Solaris sh has this property? Or is this a bug?

A: 

Bourne shell does this - create a child process - for loops and other constructs. It is expected behavior. It is not a bug in the sense that anybody using it 'knows' this problem exists. Which is a bad assumpotion sometimes.

DO NOT develop in Bourne except for system (example: startup/shutdown) scripts in Solaris. Use a POSIX shell: ksh, bash, instead. The default shell for root must be the Bourne shell, if it is not the system will cannot boot. This is an artifact of old System V.

The same kind of caveat exists for coding in csh. It is not ready for prime-time either.

jim mcnamara
I believe bash is only POSIX compliant with --posix option.
Anders
I believe that bash is not POSIX compliant even with --posix option, but that is another story :) Try, for example, `echo {a,b}`. In POSIX shell it should print `{a,b}`.
Roman Cheplyaka
You are correct sir, http://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html also clearly states "will cause Bash to conform more closely to the posix standard"
Anders
Hmm, more correctly: only "Two of Sun's Bourne shells do this on loops with indirection". Note that none of the other Bourne shells that I listed do this (eg AIX), so I can't really agree that this is "expected". Also the requirement for root's shell does not exist for Solaris 10 (my home box happily uses bash).
Martin Carpenter
+1  A: 

I would say this is a violation of the POSIX standard.

Command substitution, commands that are grouped with parentheses, and asynchronous lists shall be executed in a subshell environment. Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.

Source: Shell Command Language, section 2.12.

Roman Cheplyaka
Is while considered a command?
Anders
Yes, here is its derivation using the shell grammar (which can be found in the above linked document): `command -> compound_command -> while_clause`
Roman Cheplyaka
The `/bin/sh` command on Solaris 10 and earlier releases is documented as not being POSIX compliant - for POSIX compliance you need to use `/usr/xpg4/bin/sh` (which is actually based on ksh88 instead of Bourne shell).
alanc
+1 for great link!2.9.1: "If there is no command name, any redirections shall be performed in a subshell environment". I wonder if that's where this comes from, in some former specification that doesn't consider while to be a command (as Anders suggests)?
Martin Carpenter
@alanc, thank you for that information.
Anders
Martin: section 2.9.1 is named *Simple Commands* (as opposed to `while`, which is *compound command*), and so is irrelevant here. What that sentence means is that command like `> /dev/null` (yes, such commands are allowed by shell's syntax), which has no command name, should not affect current execution environment.
Roman Cheplyaka