Home > Enterprise >  Bash Script - If Pyscript Returns Non-zero, Write Errors to Output File AND Quite Bash Script
Bash Script - If Pyscript Returns Non-zero, Write Errors to Output File AND Quite Bash Script

Time:07-21

Have the below in a bash script -

python3 run_tests.py 2>&1 | tee tests.log

If I run python3 run_tests.py alone, I can do the below to exit the script:

python3 run_tests.py

if [ $? -ne 0 ]; then 
   echo 'ERROR: pytest failed, exiting ...'
   exit $?

However, the above working code doesn't write the output of pytest to a file.

When I run python3 run_tests.py 2>&1 | tee tests.log, the output of pytest will output to the file, but this always returns status 0, since the output job successfully ran.

I need a way to somehow capture the returned code of the python script tests prior to writing to the file. Either that, or something that accomplishes the same end result of quitting the job if a test fails while also getting the failures in the output file.

Any help would be appreciated! :)

CodePudding user response:

The exit status of a pipeline is the status of the last command, so $? is the status of tee, not pytest.

In bash you can use the $PIPESTATUS array to get the status of each command in the pipeline.

python3 run_tests.py 2>&1 | tee tests.log
status=${PIPESTATUS[0]} # status of run_tests.py
if [ $status -ne 0 ]; then
    echo 'ERROR: pytest failed, exiting ...'
    exit $status
fi

Note that you need to save the status in another variable, because $? and $PIPESTATUS are updated after each command.

CodePudding user response:

I don't have python on my system so using awk instead:

$ { awk 'BEGIN{print "foo"; exit 1}'; ret="$?"; } > >(tee tests.log)
foo
$ echo "$ret"
1
$ cat tests.log
foo

or if you want a script:

$ cat tst.sh
#!/usr/bin/env bash

#########
exec 3>&1                         # save fd 1 (stdout) in fd 3 to restore later

exec > >(tee tests.log)           # redirect stdout of this script to go to tee

awk 'BEGIN{print "foo"; exit 1}'  # run whatever command you want

ret="$?"                          # save that command's exit status

exec 1>&3; 3>&-                   # restore stdout and close fd 3
#########

echo "here's the result:"

echo "$ret"

cat tests.log

$ ./tst.sh
foo
here's the result:
1
foo

Obviously just test the value of ret to exit or not, e.g.:

if (( ret != 0 )); then
    echo 'the sky is falling' >&2
    exit "$ret"
fi
  • Related