Immediately tell which output was sent to stderr

8

4

When automating a task, it is sensible to test it first manually. It would be helpful, though, if any data going to stderr was immediately recognizeable as such, and distinguishable from the data going to stdout, and to have all the output together so it is obvious what the sequence of events is.

One last touch that would be nice is if, at program exit, it printed its return code.

All of these things would aid in automating. Yes, I can echo the return code when a program finishes, and yes, I can redirect stdout and stderr; what I'd really like it some shell, script, or easy-to-use redirector that shows stdout in black, shows stderr interleaved with it in red, and prints the exit code at the end.

Is there such a beast? [If it matters, I'm using Bash 3.2 on Mac OS X].


Update: Sorry it has been months since I've looked at this. I've come up with a simple test script:

#!/usr/bin/env python
import sys

print "this is stdout"
print >> sys.stderr, "this is stderr"
print "this is stdout again"

In my testing (and probably due to the way things are buffered), rse and hilite display everything from stdout and then everything from stderr. The fifo method gets the order right but appears to colourize everything following the stderr line. ind complained about my stdin and stderr lines, and then put the output from stderr last.

Most of these solutions are workable, as it is not atypical for only the last output to go to stderr, but still, it'd be nice to have something that worked slightly better.

Clinton Blackmore

Posted 2009-08-24T16:16:59.103

Reputation: 992

If you are lazy (or have sore fingers) like me you can grab a subshell with the below solutions (e.g. rse zsh) and now all commands colorize stderr. – bias – 2011-04-19T03:43:41.620

Answers

3

You can also check out stderred: https://github.com/sickill/stderred

sickill

Posted 2009-08-24T16:16:59.103

Reputation: 406

Unfortunately, stderred breaks "open" and "mvim" for Mac users like the OP. – AlcubierreDrive – 2011-12-26T08:45:57.790

This works very nicely, and gets the output order in the correct fashion due to the way it works. Set it up once, and turn it on in your profile, and you get red messages whenever stderr is written to. – Clinton Blackmore – 2012-10-29T15:48:17.663

1

@JonRodriguez, it appears to me that the issue with the "open" command has been fixed.

– Clinton Blackmore – 2012-10-29T15:50:58.330

9

I just devised a crazy method involving FIFOs.

$ mkfifo foo
$ grep --color . foo &
$ your_command 2>foo

If you'd like the stderr output separate, you can open up two separate shells and run "grep --color . foo" in one without the &, then run the command in the other (still with the 2>foo). You'll get the stderr in the grep one and the stdout in the main one.

This works because the stderr output is routed through the FIFO into grep --color, whose default color is red (at least it is for me). When you're done, just rm the FIFO (rm foo).

Caveat: I'm really not sure how this will handle output order, you'll have to test it out.

jtbandes

Posted 2009-08-24T16:16:59.103

Reputation: 8 350

That's pretty slick. – Clinton Blackmore – 2010-04-07T22:01:44.763

7

Yes, this is possible. Look at the section "Make STDERR red" on this site for a working example.

The basic code is this

# Red STDERR
# rse <command string>
function rse()
{
    # We need to wrap each phrase of the command in quotes to preserve arguments that contain whitespace
    # Execute the command, swap STDOUT and STDERR, colour STDOUT, swap back
    ((eval $(for phrase in "$@"; do echo -n "'$phrase' "; done)) 3>&1 1>&2 2>&3 | sed -e "s/^\(.*\)$/$(echo -en \\033)[31;1m\1$(echo -en \\033)[0m/") 3>&1 1>&2 2>&3
}

A brief explanation is given in the function itself. What is does is move STDOUT and STDERR about, so sed gets STDERR in 1, colors it, and then swaps it back. Think of file stream 3 as a temp variable here.

The call is pretty simple

rse commands

However, certain invocations will not work as expected; the caveats are all provided on the linked page.

Btw, I think it is also possible to come with a solution of the form

commands | rse 

where rse will colorize the output.

I also found this hilite project that seems to do this. I haven't tried it out, but it might be what you're looking for.

hilite is a tiny utility which executes the command you specify, highlighting anything printed to stderr. It is designed mainly for use with builds, to make warnings and errors stick out like a sore cliche.

Other related projects:

user4358

Posted 2009-08-24T16:16:59.103

Reputation:

rse and hilite are pretty close to what I want. – Clinton Blackmore – 2010-04-07T22:34:47.320

1

Another program is ind:

http :// www.habets.pp.se/synscan/programs.php?prog=ind (you have to assemble the hyperlink yourself, I don't have enough points for more than one per answer). There is a screenshot and even a screencast there.

It runs the subprocess in a pty, which the others probably don't. This can matter where order matters (it often does), since stderr is immediately flushed in terminals and stdout is fully buffered when it's not a tty.

For a full explanation, see this: http://blog.habets.pp.se/2008/06/Buffering-in-pipes

Also, ind works with interactive programs and control characters. Bash works just like normal when started with "ind bash -i".

This could work to give you colors while preserving Ctrl-P et.al.

ind -P $(echo -ne '\033[31;1m') -p $(echo -ne '\033[0m') bash -i

Thomas

Posted 2009-08-24T16:16:59.103

Reputation: 423

1

Here is a lot of responses for highlighting the stderr output yet. I can only add one pretty easy - in one row, which you attach to the command:

command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m"; done)

But you have to add this after command each time.

I, personally, like the possibility mentioned by @nagul , the rse function added to bashrc.

But I want to add the solution for printing the exit code. You can add this value to the beginning of your bash prompt row:

hostname$ command
  Some error occurred. Returned exit code.
EC hostname$

Where EC is exit code of the command.

I have it set in the way, that when the exit code is 0, it will be not printed, but any other value is printed before next prompt in red color.

The whole trick is done in ~/.bashrc:

my_prompt() {
 EXITSTATUS="$?"
 RED="\[\033[1;31m\]"
 OFF="\[\033[m\]"

PROMPT="${debian_chroot:+($debian_chroot)}\h \$ "

if [ "${EXITSTATUS}" -eq 0 ]; then
   PS1="${PROMPT}"
else
   PS1="${RED}$EXITSTATUS${OFF} ${PROMPT}"
fi
}

PROMPT_COMMAND=my_prompt

The prompt line is by default defined by PS1 variable. Copy whatever you have here into the variable PROMPT and then create the PS1 variable with or without exit code.

Bash will show the information in PS1 variable in the prompt.

srnka

Posted 2009-08-24T16:16:59.103

Reputation: 195

This is exactly what I was looking for, thanks! – Dylon – 2017-10-20T20:51:29.717

1

there's annotate-output utility (devscripts Debian package), if you would like to do it without colors

$ annotate-output /tmp/test.py    
14:24:57 I: Started /tmp/test.py
14:24:57 E: this is stderr
14:24:57 O: this is stdout
14:24:57 O: this is stdout again
14:24:57 I: Finished with exitcode 0

mykhal

Posted 2009-08-24T16:16:59.103

Reputation: 292