How to use stdout and stderr io-redirection to get the correct error / warning messages from a program?

I have a program that outputs to stdout and stderr, but does not use them correctly. Some errors go to stdout, some go to stderr, and non error stuff goes to stderr and it prints way a lot of information about stdout. To fix this, I want to make a pipeline:

  • Save all output $cmd(from stderr and stdout) to a file $logfile(do not print it on the screen).
  • Filter out all warnings and error messages on stderr and stdout (from warning | error to an empty line) and color only the words "error" (redirect the output to stderr).
  • Save the output of step 2 to a file $logfile:r.stderr.
  • Exit with the correct exit code for the command.

So far I have this:

$!/bin/zsh
# using zsh 4.2.0
setopt no_multios

# Don't error out if sed or grep don't find a match:
alias -g grep_err_warn="(sed -n '/error\|warning/I,/^$/p' || true)"
alias -g color_err="(grep --color -i -C 1000 error 1>&2 || true)"
alias -g filter='tee $logfile | grep_err_warn | tee $logfile:r.stderr | color_err'

# use {} around command to avoid possible race conditions:
{ eval $cmd } 2>&1 | filter
exit $pipestatus[1]

I tried a lot of things but can't make it work. I read "From Bash to Z Shell", a lot of posts, etc. My problems currently:

  • Only stdin is included in the filter

Note. $cmdis a shell script that calls binary with a prefix /usr/bin/time -p. This seems to be causing problems with the pipelines, and so I end the command in {…}, all the output goes to the channel.

+3
source share
3 answers

The original post was mostly correct, with the exception of Gilles optimization (to disable set -e, therefore, || truenot needed.

#!/bin/zsh
# using zsh 4.2.0
setopt no_multios
#setopt no_errexit # set -e # don't turn this on

{ eval $cmd } 2>&1 |
tee $logfile |
sed -n '/error\|warning/I,/^$/p' |
tee $logfile:r.stderr |
grep --color -i -C 1000 error 1>&2
exit $pipestatus[1]

, , stdout stderr, , sed -n '/error\|warning/I,/^$/p' ( ) , , , .

+1

zsh.

, {..} 'd .

`} '.

, bash, , stderr stdout.

{ eval $cmd ; } 2>&1 | filter
# ----------^

,

$cmd (form stderr stdout) $logfile

$logfile . ( stderr),

yourCommand 2>&1 | tee ${logFile} | ....

, .

P.S. , , , , / + ( -) .

+2

Do not use aliases in scripts, use functions (global aliases are especially looking for problems). Not that you really need the features here. You also don't need it || true(if you are not working under set -e, in which case you should disable it here). Also, your script looks fine; what is he choking?

{ eval $cmd } |
tee $logfile |
sed -n '/error\|warning/I,/^$/p' |
tee $logfile:r.stderr |
grep --color -i -C 1000 error 1>&2
exit $pipestatus[1]

I'm also not sure what you meant by the expression sed; I do not quite understand your requirement 2.

+1
source

All Articles