243

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.

5
  • 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
    Commented Jul 15, 2016 at 8:25
  • 7
    @triplee Not an exact duplicate, is it? Pipe vs. redirect to file? Commented Jul 26, 2016 at 14:02
  • @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
    Commented Jul 26, 2016 at 16:33
  • 16
    @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". Commented Jul 26, 2016 at 16:43
  • 3
    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. Commented May 5, 2017 at 13:23

3 Answers 3

239

(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 1>&2. This redirects stdout (file descriptor 1) to stderr (file descriptor 2), 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
6
  • Thanks for the clarification on &>>. I've corrected my question. Commented May 11, 2013 at 13:16
  • 24
    I added your example to my answer, just in case it was not obvious based on my given examples. As a side-note, you can also use the bash-specific |& instead of 2>&1 |. Commented May 11, 2013 at 13:21
  • 18
    Side note about the shortcut |& proposed by @AdrianFrühwirth for future readers: this feature is only supported with bash version 4+. If you're using 3 or below, you have to stick with 2>&1 |.
    – tomocafe
    Commented Apr 21, 2014 at 18:30
  • 6
    Bash redirection is very well explained here. @AdrianFrühwirth has done a good job, the link pasted goes even further. Sometimes, I wish the official Bash documentation was that good. Commented Mar 13, 2015 at 3:07
  • 1
    @AdrianFrühwirth FYI: your first example references 2>&1 in the description but actually uses 1&2 in the code.
    – JESii
    Commented Mar 17, 2022 at 22:36
201

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.

8
  • 1
    Thanks for adding this for completeness. I'm going to keep the other answer correct as many folks are still using bash pre-4.0. But this is useful. Commented May 9, 2016 at 9:30
  • 15
    Most notably perhaps, the Bash that ships on macOS is too old to support this.
    – Flimm
    Commented Jan 20, 2017 at 10:21
  • 1
    @Flimm but the zsh isn't
    – Trenton
    Commented Feb 13, 2017 at 21:41
  • 1
    Since ksh uses |& for coproc, this seems like a bad choice for an unnecessary shorthand. I hate to see lines with a stack of dups and redirections as much as the next guy, but there's something to be said for being explicit....and I apologize that this comment doesn't add much. I just wanted to express distaste for the shorthand without downvoting an actually helpful answer, because it's good that people see this. I didn't know this, so thanks for making me aware. Commented Oct 2, 2017 at 14:59
  • 1
    @PaulHodges I agree that it's not portable - I mainly like using it for interactive Bash sessions to avoid typing too much. Commented Oct 2, 2017 at 16:40
3

If you want to pipe STDOUT and STDERR to different subshells instead of both to the same one (as |& / 2>&1 does), I use this:

producer \
  >  >( stdout_pipeline... ) \
  2> >( stderr_pipeline... ) \
  ...

While this uses the redirection operator, it uses pipes under the hood to connect the producer to the subshells.

You can process multiple output streams (2 is not the limit) this way, and also pipe (potentially multiple) input streams from subshells in a similar way with the penguin operator ([n]< <(...)).

Not the answer you're looking for? Browse other questions tagged or ask your own question.