Search code examples
shellposixpipeline

Is pipeline guaranteed to create a subshell in any POSIX shell?


This shell script behaves as expected.

trap 'echo exit' EXIT

foo()
{
    exit
}

echo begin
foo
echo end

Here is the output.

$ sh foo.sh
begin
exit

This shows that the script exits while executing foo.

Now see the following script.

trap 'echo exit' EXIT

foo()
{
    exit
}

echo begin
foo | cat
echo end

The only difference here is that the output of foo is being piped into `cat. Now the output looks like the following.

begin
end
exit

This shows that the script does not exit while executing foo because end is printed.

I believe this happens because in bash a pipeline causes a subshell to be opened, so foo | cat is equivalent to (foo) | cat.

Is this behaviour guaranteed in any POSIX shell? I could not find anything in the POSIX standard at http://pubs.opengroup.org/onlinepubs/9699919799/ that implies that a pipeline must lead to a subshell. Can someone confirm if this behaviour can be relied upon?


Solution

  • In 2.12 Shell Execution Environment you find this quote:

    A subshell environment shall be created as a duplicate of the shell environment, except that signal traps that are not being ignored shall be set to the default action. Changes made to the subshell environment shall not affect the shell environment. 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.

    Where the key sentence for this question is

    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

    So without the extension (which bash uses for things like lastpipe and, I thought, for the first element in a pipeline as well but apparently not or at least not always) it looks like you can assume there will be a subshell for each part of the pipeline but the exception means you can't quite count on that.