190
votes

It seems that newer versions of bash have the &> operator, which (if I understand correctly), redirects both stdout and stderr to a file (&>> appends to the file instead, as Adrian clarified).

What's the simplest way to achieve the same thing, but instead piping to another command?

For example, in this line:

cmd-doesnt-respect-difference-between-stdout-and-stderr | grep -i SomeError

I'd like the grep to match on content both in stdout and stderr (effectively, have them combined into one stream).

Note: this question is asking about piping, not redirecting - so it is not a duplicate of the question it's currently marked as a duplicate of.

2
See the second answer (stackoverflow.com/a/637834/1129642) on the linked question for the correct way to pipe both stdout and stderr. No need for another question.Marki555
@triplee Not an exact duplicate, is it? Pipe vs. redirect to file?Benjamin W.
@BenjaminW There is at least one answer there which solves both scenarios, though it's not the accepted answer. This is a fairly common question so we could probably find a better duplicate, or ask a moderator to merge these - or even, in the worst case, craft an entirely new canonical for this topic. If you find a better dupe, by all means propose it. Thanks in advance.tripleee
@tripleee Solves, yes, but none of the answers use the |& shortcut, which I think is by far the most convenient solution to "redirect both stdout and stderr to a pipe".Benjamin W.
This is not a duplicate of the linked question, and it wasn't clear that Marko's answer did what I wanted. Also, it doesn't mention |&. Voting to reopen.Martin Bonner supports Monica

2 Answers

196
votes

(Note that &>>file appends to a file while &> would redirect and overwrite a previously existing file.)

To combine stdout and stderr you would redirect the latter to the former using 2>&1. This redirects stderr (file descriptor 2) to stdout (file descriptor 1), e.g.:

$ { echo "stdout"; echo "stderr" 1>&2; } | grep -v std
stderr
$

stdout goes to stdout, stderr goes to stderr. grep only sees stdout, hence stderr prints to the terminal.

On the other hand:

$ { echo "stdout"; echo "stderr" 1>&2; } 2>&1 | grep -v std
$

After writing to both stdout and stderr, 2>&1 redirects stderr back to stdout and grep sees both strings on stdin, thus filters out both.

You can read more about redirection here.

Regarding your example (POSIX):

cmd-doesnt-respect-difference-between-stdout-and-stderr 2>&1 | grep -i SomeError

or, using >=bash-4:

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError
135
votes

Bash has a shorthand for 2>&1 |, namely |&, which pipes both stdout and stderr (see the manual):

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError

This was introduced in Bash 4.0, see the release notes.