How to tell if output of a command or shell script is stdout or stderr

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?)?

Asked By: KM.

||

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)

Answered By: klerk

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.

Answered By: godlygeek

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
Answered By: Mark Plotnick

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.

Answered By: Carlos Campderrós

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?

Answered By: mr.spuratic

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
Answered By: mlgoth

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
Answered By: papu

You can make use of grep for this very easily:

$ ls -l test | grep .
ls: cannot access 'test': No such file or directory

This assumes that your grep output is coloured (this is the default on most distros).

This will result in stdout being highlighted with the default grep colour, for example:

$ (echo "this is stdout"; echo "this is stderr" >&2) | grep .
this is stderr
this is stdout

The first line of output is white while the second is coloured. This might be the opposite of what you want if your default grep colour is red. If you explicitly want to set stdout to green you could do this to set the grep colours to green:

$ GREP_COLORS='ms=01;32'
$ (echo "this is stdout"; echo "this is stderr" >&2) | grep .

If you explicitly want to get red output for stderr:

$ GREP_COLORS='ms=01;31'
$ (echo "this is stdout"; echo "this is stderr" >&2) 2> >(grep .)

If you really want both stderr and stdout to be specific colours then you can do this:

$ (echo "this is stdout"; echo "this is stderr" >&2) 2> >(GREP_COLORS='ms=01;31' grep .) 1> >(GREP_COLORS='ms=01;32' grep .)
Answered By: htaccess
Categories: Answers Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.