Sandy Chapman
Sandy Chapman

Reputation: 11341

Why does bash suppress stdout when exit 0 in ERR trap?

I was experimenting with setting up an ERR trap in bash and noticed some strange behaviour. Bash seems to not output my echo command to the console when I run this script if the exit code is 0, however, if the exit code is non-zero, then the text is outputted. Is this a bug in bash? Or is there some explanation for this?

./testing.sh:

#!/bin/bash

set -eE

handleerror() {
  echo "TEST"
  exit 0
}
trap "handleerror" ERR

OUTPUT=$(mkdir test/test 2>&1)

If I run the script above, it outputs nothing. If I change the exit 0 line to exit 1, I see the following:

> ./testing.sh
TEST

For reference:

> bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

Upvotes: 4

Views: 80

Answers (1)

chepner
chepner

Reputation: 532303

Short answer: the output isn't suppressed; it's captured by the command substitution. Changing the exit status of handleerror changes the number of times it gets called: once inside the command substitution, and once outside. Run bash -x testing.sh to see the difference.


You have to consider when handlerror actually gets called. The failure of mkdir triggers the call, and since handleerror is called inside the command substitution, its output is captured and assigned to OUTPUT. If you add echo "$OUTPUT" to the end of the script, you'll see

mkdir: test: No such file or directory
TEST

as the output of the script. This line executes because the 0 exit status of handleerror prevents set -e from exiting the script early.

Now, change exit 0 to exit 1. The sequence starts the same: mkdir fails, handleerror is called, and its output is captured by the command substitution. But, now the exit status of handleerror itself is 1, which makes the exit status of the command substitution and also the assignment statement 1 as well. This does two things: it causes set -e to abort the script before echo "$OUTPUT" runs, and it causes handleerror to run a second time. Now when you run the script, all you see is

TEST

resulting from the second call to handleerror.

Upvotes: 5

Related Questions