8

I'd like to check whether a line printed by a command contains an error message, but I'd like to also print all the output from the command (for make logs). Is there some way to get all the output of a command (unmodified) and an exit code based on the contents of that output? The closest workaround I could think about was my_command | grep -C 99999999 '^Error'.

This is similar but distinct to this question, since I care about the exit code and don't want colouring.

5
  • How about grep -E '^Error|$'?
    – cuonglm
    Sep 30, 2014 at 10:07
  • @Gnouc that will give $?==0 all the time.
    – jimmij
    Sep 30, 2014 at 10:30
  • @jimmij - if you are using bash you can use 'set -o pipefail' and the return code will be not be of grep but the command that failed.
    – user14755
    Sep 30, 2014 at 10:41
  • @DarkHeart OP wants grep exit code, not other command.
    – jimmij
    Sep 30, 2014 at 10:46
  • @jimmij - yes sorry, i misread.
    – user14755
    Sep 30, 2014 at 10:52

4 Answers 4

9

Use tee and redirect it to stderr

my_command | tee /dev/stderr | grep -q '^Error'

It will save grep exit status and duplicate all the output to stderr which is visible in console. If you need it in stdout you can redirect it there later like this:

( my_command | tee /dev/stderr | grep -q '^Error' ) 2>&1

Note that grep will output nothing, but it will be on tee.

1
  • As soon as grep matches the whole will stop.
    – Matteo
    Apr 14, 2022 at 4:52
2

You can do this with AWK:

command 2>&1 | awk '/^Error/{exit_code=1;}/^/ END{ exit !exit_code}'

This will print all the output lines and return 0 if it finds Error and return 1 if it doesn't.

1
  • 1
    I had to add a print command 2>&1 | awk '/^Error/{exit_code=1;}/^/{print} END{ exit !exit_code}' to get this to work. Otherwise it gave mea syntax error. Note sure if this is right. Jun 7, 2022 at 3:16
0

You can do it with sed as well!

Here's a function to Print all + Highlight matches + Return exit code (5) if no match found:

search_regex()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed '/'"${pattern}"'/,${s//'$esc'[32m&'$esc'[0m/g;b};$q5' "$@"
}

$ echo -e "What's up\nMr. Jones?" | search_regex "on\|up"

What's up
Mr. Jones?

0

Here's how you do it with sed if you don't want coloring, i.e. you want exact output:

my_command | sed '/^Error/,$b;$q1'

And since this is a bit cryptic, I try to explain how it works:

  • by default already, sed prints every line from stdin to stdout, so we've already achieved our first goal of printing every line
  • /^Error/,$ then defines a range from the line that matches the pattern /^Error/ to the end of the file ($ means the last line).
  • on this range, execute command b. b branches (i.e. jumps) to a label. If the label is omitted, it branches to end of script. sed returns with status code 0.
  • if no line matches the pattern /^Error, the range command is not executed, thus we're not jumping to the end of script. Instead, the next command is executed: $q1.
  • $q1 simply means to run command q1 on the last line ($). q1 ends the script, with status code 1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .