6

In a shell script I'm using a code-block with curly brackets to pipe all output to console and a log-file with tee.

#!/bin/bash

{
  echo "Foo bar"
  echo "foo bar on STDERR" >&2
  ERRL=66
  exit 99
} 2>&1 | tee log-file.log

(This is only a small demo script, the original is much more complex)

The problem is, that the line exit 99 has no effect, the script ends with exit code 0. (This is the exit code of the tee command, I think)

I tried to add the line exit $ERRL at the end of the script, but it shows, that the variable $ERRL is empty outside the curly brackets.

What can I do, to end the script with an error code when something went wrong within the code-block -- without loosing the output to the log-file?

2
  • Check the bash PIPESTATUS array. See tldp.org/LDP/abs/html/internalvariables.html Commented Jan 14, 2015 at 16:55
  • 1
    Boo, hiss re: linking to the ABS -- it's rather notorious for being only sporadically maintained and, when not outright inaccurate, showcasing bad practices. Granted, that specific page isn't so bad (a little out-of-date, but nothing obviously outright wrong), but reviewing the ones immediately prior, section 9.2 is missing outright a number of bash 4.3 updates, and shows an extremely error-prone way of identifying variable types when reliable ones are available. Commented Jan 14, 2015 at 17:10

2 Answers 2

5

The least-intrusive way to redirect the output of your entire script is to do so once, up-front, without any blocking constructs involved:

exec > >(tee log-file.log) 2>&1 # redirect stdout and stderr to a pipe to tee

echo "Foo bar"
echo "foo bar on STDERR" >&2
ERRL=66
exit 99

Alternate options include using the pipefail setting...

set -o pipefail
{ ... } 2>&1 | tee log-file.log

...or explicitly pulling the exit status out after-the-fact:

{ ... } 2>&1 | tee log-file.log
exit "${PIPESTATUS[0]}"

...or just using a redirection that isn't a pipeline:

{ ... } > >(tee log-file.log) 2>&1
Sign up to request clarification or add additional context in comments.

1 Comment

I choose the PIPESTATUS-solution for my script, because I just have to add one line. But the next time I write something similar I'll choose the exec-solution.
0

That is because the exit code is the one of the last command in a pipeline, unless you have set -o pipefail before the pipe. As @jimmcnamara hinted, the $PIPESTATUS array contains the exit codes of each of the commands in your pipeline, in the same order as the original pipeline.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.