22

Why does the output of some Linux programs go to neither STDOUT nor STDERR?

Actually, I want to know how to reliably capture all program output, no matter what 'stream' it uses. The problem I have is that some programs do not seem to let their output be captured.

An example is the 'time' command:

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

or

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

Why do I see output both times? I expected it all to be piped into /dev/null.

What output stream is time using, and how can I pipe it into a file?

One way to work around the problem is to create a Bash script, for example, combine.sh containing this command:

$@ 2>&1

Then the output of 'time' can be captured in the correct way:

combine.sh time sleep 1 &> /dev/null

(no output is seen - correct)

Is there a way to achieve what I want without using a separate combine script?

1
  • 4
    first you should reverse the order: 2>&1 > /dev/null means "2 now goes to where 1 goes (ie, the terminal, by default), and then 1 now goes to /dev/null (but 2 still goes to the terminal!). use >/dev/null 2>&1 to say "1 goes now to /dev/null, then 2 goes to where 1 goes (ie, also to /dev/null) . This still won't work here as the builtin 'time' won't get redirected, but is more generally correct (for example it would work if you use /usr/bin/time). Think about "2>&1" as copying 1's "direction" into 2, not as 2 going to 1 Jul 4, 2013 at 12:27

4 Answers 4

40

This question is addressed in BashFAQ/032. In your example, you would:

{ time sleep 1; } 2> /dev/null

The reason why

time sleep 1 2>/dev/null

doesn't behave how you're expecting is because with that syntax, you'll want to time the command sleep 1 2>/dev/null (yes, the command sleep 1 with stderr redirected to /dev/null). The builtin time works that way so as to make this actually possible.

The bash builtin can actually do this because... well, it's a builtin. Such a behavior would be impossible with the external command time usually located in /usr/bin. Indeed:

$ /usr/bin/time sleep 1 2>/dev/null
$

Now, the answer to your question

Why does the output of some linux programs go to neither STDOUT nor STDERR?

is: it does, the output goes to stdout or stderr.

Hope this helps!

3
  • 2
    you can create other fd and have commands explicitely go to those (ex: in bash script: exec 3>/some/file ; ls >&3 ; ) Jul 4, 2013 at 12:25
  • @OlivierDulac Sure, or even simpler with the coproc builtin. But it's not the case for the time builtin. Jul 4, 2013 at 16:02
  • @gniourf-gniourf: I was commenting because of your sentence "the output goes to stdout or stderr" ^^ Jul 4, 2013 at 17:04
16

Your particular question about time builtin has been answered, but there are some commands that don't write either to stdout or to stderr. A classic example is the Unix command crypt. crypt with no arguments encrypts standard input stdin and writes it to standard output stdout. It prompts the user for a password using getpass(), which by default outputs a prompt to /dev/tty. /dev/tty is the current terminal device. Writing to /dev/tty has the effect of writing to the current terminal (if there is one, see isatty()).

The reason crypt can't write to stdout is because it writes encrypted output to stdout. Also, it's better to prompt to /dev/tty instead of writing to stderr so that if a user redirects stdout and stderr, the prompt is still seen. (For the same reason, crypt can't read the password from stdin, since it's being used to read the data to encrypt.)

3
  • 4
    +1. Less relevant for the OP, but more relevant for everyone coming across "Why does the output of some linux programs go to neither STDOUT nor STDERR?" via Google. :-)
    – ruakh
    Jul 3, 2013 at 23:22
  • Yes, I too came here via Google looking for this. Specifically xattr on macOS writes failures, such as xattr: No such file: /Volumes/blah-blah-volume/blah-blah-file to neither stdout nor stderr. I have to re-run a very, very long-running xattr job because I'd run it in screen, piping stdout and stderr to respective files, only to find out both were empty and all failure messages lost except for the last few handfuls still in the screen's buffer. Is there a way to pipe /dev/tty to a file to capture this output? Mar 17 at 6:45
  • @DanielSmedegaardBuus you might be able to use script command (e.g., see unix.stackexchange.com/a/647847/31226)
    – Alok
    Mar 21 at 3:38
0

time sleep 1 > /dev/null 2>&1 # redirects "sleep's" output do null. Then, "time" writes its own output, with no redirection. It is like "time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # runs "time sleep 1", then redirects its output to null.

[]s

-1

The problem in your case is that the redirection works in another way. You wrote

time sleep 1 2>&1 > /dev/null

This redirects the standard output to /dev/null and then redirects the standard error to standard output.

To redirect all output you have to write

time sleep 1 > /dev/null 2>&1 

Then the standard error will be redirected to the standard output and after that all the standard output (containing the standard error) will be redirected to /dev/null.

2
  • This doesn't work with the bash builtin time. See my answer for some explanations. Jul 3, 2013 at 11:57
  • +1 because this is a useful answer to a similar question. Although @Olivier explains it better in the comment to the question above. Oct 6, 2014 at 9:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .