32

Let us say I run a command or shell script, and it gives me output. Without knowing the internals of this command or shell script, how does one determine if is the output was from stderr or stdout?

For e.g.,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

vs

ls -ld /test
ls: /test: No such file or directory

How do I ascertain that the first command printed to stdout and the second to stderr (did it?)?

  • 1
    What problem are you trying to solve here? – Kenster Feb 23 '15 at 22:20
  • 3
    Was afraid someone would ask that; none really, mostly curious and hoping to improve my understanding of redirection. – KM. Feb 23 '15 at 22:22
  • 7
    You could put stderred in your shell environment's LD_PRELOAD to get stdout and stderr in different colours. Here's a related question in that vein. – Anko Feb 24 '15 at 11:26
18

There's no way to tell once the output has already been printed. In this case, both stdout and stderr are connected to the terminal, so the information about which stream was written to was already lost by the time the text appeared on your terminal; they were combined by the program before ever making it to the terminal.

What you can do, in a case like the above, would be to run the command with stdout and stderr redirected to different places and see what happens. Or run it twice, once with stdout redirected to /dev/null and once with stderr redirected to /dev/null, and see which of those cases results in the text showing up.

You can redirect stdout to /dev/null by tacking >/dev/null on the end of the command line, and you can redirect stderr to /dev/null by adding 2>/dev/null.

9

You can redirect stdout using > file, and redirect stderr using 2> file. Many modern shells support redirecting to commands, so you can use sed to highlight which output comes from which stream:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory
  • Very nice! It would be great if one could highlight the lines in colors rather than prefix. – dotancohen Feb 24 '15 at 8:57
  • 3
    @dotancohen: One can! Eg, (echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/') – PM 2Ring Feb 24 '15 at 11:30
  • Note that if there's mixed output from stdout and stderr, first stdout will be printed, then stderr. – nyuszika7h Feb 24 '15 at 14:51
5

The annotate-output script from Debian's devscripts lets you do this selectively:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

The second column indicates stdout and stderr with O and E respectively.

There are some caveats, the main one being as noted in the other answers: you can't do this after the fact. Neither the shell nor the terminal are aware of how an arbitrary program uses its file descriptors, though the shell is responsible for setting them up initially.

This method uses fifos, writing to a fifo can behave differently than writing to a tty, and writing to two different fifos is definitely different (potential timing/interleaving issues). Also, it's not suitable for interactive use, e.g. annotate-output bash is not a great plan, but it's useful for many other purposes. There are many, many examples of scripts and shell functions in answers to related questions about colorising stdin/stdout/stderr, the most robust is stderrd which uses runtime modification of (most) programs to modify data written to stderr.

This question that Anko links to has good answers on that related theme: colorising the stdout/stderr output: Can I configure my shell to print STDERR and STDOUT in different colors?

  • 1
    Note that it's a bash script using while read loops and running one date command for each line of stdout or stderr, so it going to be a lot less efficient than the cmd > >(ts '%T O:') 2> >(ts '%T E:') equivalent. – Stéphane Chazelas Sep 15 '17 at 9:19
1

Apart from the other answers, it is interessant to point to /proc/$PID/fd (although it does not answer the question):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

As you see, here you can see the file descriptors opened for a process. 0 is the STDIN, 1 is the STDOUT and 2 is the STDERR. If you didn't have the STDOUT or STDERR redirected, you'd see /dev/pts/33 (in this example at least) because they would point to the terminal.

notes: /proc/$PID only exists for running processes. In this case I have used cat without arguments so it does not end until I close the STDIN. I have also executed it in the background so I have the PID immediately for the sake of this example.

0

It is not quite clear what you are asking but this might help

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

Source

If exit code is 0 it simply means that command is executed correctly (stdout), here you can find meanings if exit code is different than 0 (stderr)

  • Very interesting! I would've never connected exit statuses with redirection. Does zero imply stdout and non-zero imply stderr? – KM. Feb 23 '15 at 22:25
  • 7
    @KM., no. I'd say it strongly correlates, but there's nothing that stops a program from writing to stderr and returning a good error code, or writing to stdout and returning a bad error code. In fact, try find /root - assuming you're not running as root, you should get 2 lines printed out - "/root" gets printed to stdout, and "find: /root: Permission denied" gets printed to stderr. And find returns a bad return code. – godlygeek Feb 23 '15 at 22:37
  • op's problem is clear that how to tell which is stdout or stderr. – it_is_a_literature Jul 25 '17 at 12:42
0

Usually STDERR will have the program name prepended to the message with a colon.

Example:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed
-1

To capture and test for error output:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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