#694628 bash: behaviour of "|&" doesn't match documentation

Package:
bash
Source:
bash
Description:
GNU Bourne Again SHell
Submitter:
Frank Heckenbach
Date:
2015-05-13 00:42:05 UTC
Severity:
normal
#694628#5
Date:
2012-11-28 13:39:54 UTC
From:
To:
*** Please type your report below this line ***

The manpage says:

"[1] If |& is used, the standard error of command is connected to
command2's standard input through the pipe; [2] it is shorthand for
2>&1 |.  This implicit  redirection of the standard error is
performed after any redirections specified by the command."

At first glance, [1] and [2] say the same, but that's not so, as
this example shows:

% sh -c 'echo stdout; echo stderr >&2' > /dev/null |& cat

Here, both stdout and stderr are redirected to /dev/null. That's
what [2] says, but not what [1] says.

So at the very least this is a documentation bug, and the manpage
should say:

"If |& is used, the standard error of command is connected to
whatever the standard output is connected to which may or may not be
the pipe to command2's standard input;"

However, I wonder if the behaviour is really very meaningful. Since
the "|&" token refers to the pipe syntactically, one would naively
expect that its behaviour has to do with the pipe. Of course, it's
easy to work-around by wrapping the command in a subshell which does
what I'd have expected:

% (sh -c 'echo stdout; echo stderr >&2' > /dev/null) |& cat
stderr

#694628#10
Date:
2015-05-13 00:13:00 UTC
From:
To:
As of 4.3.30 (jessie), the critical passage in the documentation has
been slightly reworded:

"If |& is used, command's standard error, in addition to its
standard output, is connected to command2's standard input through
the pipe;"

But it's still not correct. The point is, "|&" does *not* connect
the command's standard error to the pipe. It connects it to its
standard output *after* all other redirections. *Before* those
redirections, that would be the pipe, but after them, it may or may
not be. I.e. what seems to happen is:

1. redirect stdout to the pipe
2. do all explicit redirections
3. redirect stderr to stdout

So stdout and stderr are handled fundamentally differently, whereas
the wording above makes it sound like they're handled the same way.

Consider again the example from my original report:

% sh -c 'echo stdout; echo stderr >&2' > /dev/null |& cat

Outputs nothing, so the explicit redirection of stdout also affects
stderr.

In contrast to:

% sh -c 'echo stdout; echo stderr >&2' 2> /dev/null |& cat
stdout
stderr

So the explicit redirection of stderr has no effect.