tags:

views:

619

answers:

6

Guys, is there an alternative to "tee" which captures STDOUT/STDERR of the command being executed and exits with the same exit status as the processed command. Something as following:

eet -a some.log -- mycommand --foo --bar

Where "eet" is an imaginary alternative to "tee" :) (-a means append, -- separates the captured command) It shouldn't be hard to hack such a command but maybe it already exists and I'm not aware of it?

Thanks.

A: 

G'day,

Assuming bash or zsh,

my_command >>my_log 2>&1

N.B. Sequence of redirection and duplication of STDERR onto STDOUT is significant!

Edit: Oops. Didn't realise you wanted to see the output on screen as well. This will of course direct all output to the file my_log.

HTH

cheers,

Rob Wells
This sends all output to my_log, but unlike tee, it does not also show up on the console.
Steve Madsen
@Steve, you're right. My bad. )-:
Rob Wells
+4  A: 

Stumbled upon a couple of interesting solutions here http://www.perlmonks.org/?node_id=597613.

1) There is $PIPESTATUS variable available in bash:

   false | tee /dev/null
   [ $PIPESTATUS -eq 0 ] || exit $PIPESTATUS

2) And the simplest prototype of "eet" in perl may look as follows:

   open MAKE, "command 2>&1 |" or die;
   open (LOGFILE, ">>some.log") or die;
   while (<MAKE>) { print LOGFILE $_; print }
   close MAKE; # to get $?
   my $exit = $? >> 8;
   close LOGFILE;
pachanga
A: 
#!/bin/sh
logfile="$1"
shift
exec 2>&1
exec "$@" | tee "$logfile"

Hopefully this works for you.

Marko Teiste
Run this with arguments "foo false" -- should return with exit code 1 (from false), but I get 0 (presumably from tee).
Steve Madsen
My bad. Have to do it the old fashioned pipe way. PIPE=/tmp/$$.pipe;mkfifo "$PIPE";logfile="$1";shift;tee "$logfile" <"$PIPE" "$@" 2>status=$?;rm "$PIPE";exit $status
Marko Teiste
A: 
{ mycommand --foo --bar 2>&1; ret=$?; } | tee -a some.log; (exit $ret)
Peter Ericson
At least on bash, $ret is not available outside of the {list}, so this doesn't work.
Steve Madsen
+1  A: 

This works with bash:

(
  set -o pipefail
  mycommand --foo --bar | tee some.log
)

The parentheses are there to limit the effect of pipefail to just the one command.

From the bash(1) man page:

The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.
Ville Laurikari
+1  A: 

Here's an eet. Works with every Bash I can get my hands on, from 2.05b to 4.0.

#!/bin/bash
tee_args=()
while [[ $# > 0 && $1 != -- ]]; do
    tee_args=("${tee_args[@]}" "$1")
    shift
done
shift
# now ${tee_args[*]} has the arguments before --,
# and $* has the arguments after --

# redirect standard out through a pipe to tee
exec | tee "${tee_args[@]}"

# do the *real* exec of the desired program
exec "$@"

(pipefail and $PIPESTATUS are nice, but I recall them being introduced in 3.1 or thereabouts.)

ephemient
It's strange - but it doesn't work for me: jirka@debian:~/monitor$ exec | wc -c \\ 0 \\ jirka@debian:~/monitor$ exec echo a \\ a(\\ means newline)
jpalecek