1

I have a bash function like so:

run_mongo(){
  mongo foo bar baz 2>&1  # send stderr to stdout
}

unfortunately this mongo command doesn't exit with 1 if there is error, so I have to match on stdout/stderr

is there some way to exit with code > 0 with grep if there is a first match? something like this:

run_mongo | grep -e "if stdout/stderr matches this we exit with 1"

I assume the way to do this would be like so:

run_mongo | grep -e "if stdout/stderr matches" | killer

where killer is a program that dies as soon as it gets its first bit of stdin.

  • I guess killer would just be exit 1 lol, actually no it wouldn't lulz – Alexander Mills Mar 26 '18 at 23:31
  • If the mongo command exits successfully when there was an error, and there is no option to make it do otherwise, this is a bug. Please report it. That's not even a difficult bug to fix, and then developers won't have to hack around it like you're doing. – Wildcard Mar 27 '18 at 2:59
4

Yes, you can do it with grep -vz which tells grep to find lines that don't match the pattern you give it (-v) and to read the entire ionput at once (z), so that one match means the whole thing fails:

$ printf 'foo\nbar\n' | grep -zqv foo && echo no || echo yes
yes
$ printf 'foo\nbar\n' | grep -zq foo && echo no || echo yes
no

So, in your case, something like:

run_mongo(){
  mongo foo bar baz 2>&1 | grep -vzq "whatever means failure" 
}

if run_mongo; then
 echo "Worked!"
else
  echo "Failed!"
fi

If you want to avoid reading the whole output, just use another tool. Perl, for example:

mongo foo bar baz 2>&1 | perl -ne 'exit 1 if /whatever means failure/' 
  • the only question in my mind - does the pipe clean itself up consistently if the last command dies first? or if any of the non-first commands die first? I would guess no... – Alexander Mills Mar 26 '18 at 23:54
  • 1
    @AlexanderMills that's not relevant to the question you're asking, since you said the process fails without actually returning, but no it doesn't. If that's the behavior you want and assuming your default shell is bash, then you need set -o pipefail (see Get exit status of process that's piped to another). – terdon Mar 27 '18 at 0:04
  • so using set -o pipefail means the line that sets the pipe will exit with the exit status of the last command? – Alexander Mills Mar 27 '18 at 2:15
  • 1
    @AlexanderMills see help set: "pipefail the return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if no command exited with a non-zero status" – muru Mar 27 '18 at 2:51
1
echo 'if stdout/stderr matches this' |
    awk '$0 ~ "if stdout/stderr matches this" { exit 1; }' ; echo $?
0

@terdon's solution looks good, since I am a Node.js fanboy, I just wrote a program like this:

#!/usr/bin/env node

process.stdin.resume().once('data', function () {
   process.exit(1);
});

then in my bash script have:

run_mongo(){
  mongo foo bar baz 2>&1
}

exit_if_match(){
    grep "$1" | "./node_modules/.bin/imminent_suicide"
}

run_mongo "foo" "bar" | exit_if_match "errmsg"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.