68

I saw this interesting question at a comment on cyberciti.biz.

That I found I even can't find a flexible way to do this in one-line command with sh.

As far my thought for the solution is:

tmp_file=`mktemp`
(./script 2>$tmp_file >/dev/null; cat $tmp_file) | ./other-script
rm tmp_file

But you see, this is not synchronous, and fatally, it's so ugly.

Welcome to share you mind about this. :)

shouya
  • 2,863
  • 1
  • 24
  • 45
  • 3
    Did you try `./script.sh 2>&1 > /dev/null` ? – cnicutar Aug 19 '12 at 14:21
  • @cnicutar It seemed I have a wrong understanding in the start. I supposed `2>&1` will redirect `stderr` to `stdout` and the `1>/dev/null` will then redirect both them into `/dev/null`. Well I need to relearn some shell. – shouya Aug 19 '12 at 14:26
  • 1
    In my case, the `2>&1` needed to go at the end, eg: `if ping -c 1 fake.x > /dev/null 2>&1;then echo true;else echo false;fi` – Jonathan Cross Nov 20 '15 at 22:31

3 Answers3

134

You want

./script 2>&1 1>/dev/null | ./other-script

The order here is important. Let's assume stdin (fd 0), stdout (fd 1) and stderr (fd 2) are all connected to a tty initially, so

0: /dev/tty, 1: /dev/tty, 2: /dev/tty

The first thing that gets set up is the pipe. other-script's stdin gets connected to the pipe, and script's stdout gets connected to the pipe, so script's file descriptors so far look like:

0: /dev/tty, 1: pipe, 2: /dev/tty

Next, the redirections occur, from left to right. 2>&1 makes fd 2 go wherever fd 1 is currently going, which is the pipe.

0: /dev/tty, 1: pipe, 2: pipe

Lastly, 1>/dev/null redirects fd1 to /dev/null

0: /dev/tty, 1: /dev/null, 2: pipe

End result, script's stdout is silenced, and its stderr is sent through the pipe, which ends up in other-script's stdin.

Also see http://bash-hackers.org/wiki/doku.php/howto/redirection_tutorial

Also note that 1>/dev/null is synonymous to, but more explicit than >/dev/null

Greg Dubicki
  • 5,983
  • 3
  • 55
  • 68
geirha
  • 5,801
  • 1
  • 30
  • 35
  • In my edit comment I incorrectly referenced stdin instead of stdout though the edit itself is still correct. I could not see how to fix edit comment or comment on edit review so mentioning here. – DVS Jan 30 '19 at 16:43
  • @geirha Excellent. What if we have to output to >/dev/null, and stderr both to a file and screen? Thanks – Manohar Reddy Poreddy Mar 22 '20 at 12:45
  • 1
    @ManoharReddyPoreddy To output both to terminal and a file, use the `tee` command. `./script 2>&1 >/dev/null | tee file` – geirha Mar 23 '20 at 19:55
  • Apparently this doesn't work in zsh. It ends up redirecting script's stdout and stderr to the pipe. Is this a bug or a feature, I'm wondering. – Olaf Klischat Mar 02 '22 at 14:52
  • I want to log the timestamp only when my internet connection is interrupted. The below command is working as expected. `ping www.google.com 2>&1 1>/dev/null | perl -nle 'print scalar(localtime), " ", $_'` – Kharthigeyan Mar 19 '22 at 11:39
6

How about this:

./script 3>&1 1>/dev/null 2>&3 | ./other-script

The idea is to "backup" stdout descriptor, close the original stdout and then redirect strerr to saved stdout.

Its much similar to the solution provided by geirha, but its more explicit (bash coding can easily become very obscured).

Zaar Hai
  • 9,152
  • 8
  • 37
  • 45
-6

Well, that's because you can't. STDOUT and STDERR are just two files, represented by file descriptors, which are just integers, specifically 1 and 2.

What you're asking is to set descriptor 2 to /dev/null, then set descriptor 3 to the same file descriptor 2 and have that output go somewhere else.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263