paxdiablo
paxdiablo

Reputation: 882586

With bash, how can I pipe standard error into another process?

It's well known how to pipe the standard ouput of a process into another processes standard input:

proc1 | proc2

But what if I want to send the standard error of proc1 to proc2 and leave the standard output going to its current location? You would think bash would have a command along the lines of:

proc1 2| proc2

But, alas, no. Is there any way to do this?

Upvotes: 180

Views: 93956

Answers (6)

Lenik
Lenik

Reputation: 14458

((echo one out; echo -e 'two\nerr' >&2) |wc) 2> >(wc)

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 882586

You can use the following trick to swap stdout and stderr. Then you just use the regular pipe functionality.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Provided stdout and stderr both pointed to the same place at the start, this will give you what you need.

What the x>&y bit does is to change file handle x so it now sends its data to wherever file handle y currently points. For our specific case:

  • 3>&1 creates a new handle 3 which will output to the current handle 1 (original stdout), just to save it somewhere for the final bullet point below.
  • 1>&2 modifies handle 1 (stdout) to output to the current handle 2 (original stderr).
  • 2>&3- modifies handle 2 (stderr) to output to the current handle 3 (original stdout) then closes handle 3 (via the - at the end).

It's effectively the swap command you see in sorting algorithms:

temp   = value1;
value1 = value2;
value2 = temp;

Upvotes: 106

sbingner
sbingner

Reputation: 122

None of these really worked very well. The best way I found do do what you wanted is:

(command < input > output) 2>&1 | less

This only works for cases where command does not need keyboard input. eg:

(gzip -d < file.gz > file) 2>&1 | less

would put gzip errors into less

Upvotes: 3

Scot
Scot

Reputation: 2246

There is also process substitution. Which makes a process substitute for a file.
You can send stderr to a file as follows:

process1 2> file

But you can substitute a process for the file as follows:

process1 2> >(process2)

Here is a concrete example that sends stderr to both the screen and appends to a logfile

sh myscript 2> >(tee -a errlog)

Upvotes: 223

kccqzy
kccqzy

Reputation: 1598

Swapping is great as it solves the problem. Just in case you do not even need the original stdout, you can do it this way:

proc1 2>&1 1>/dev/null | proc2

The order is vital; you would not want:

proc1 >/dev/null 2>&1 | proc1

As this will redirect everything to /dev/null!

Upvotes: 35

Dennis Williamson
Dennis Williamson

Reputation: 360665

Bash 4 has this feature:

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

zsh also has this feature.

--

With other/older shells, just enter this explicitly as

FirstCommand 2>&1 | OtherCommand

Upvotes: 93

Related Questions