Search code examples
bashexit-codesubshell

Wrong exit code for variable function call assignment in subshell


I have a script which quite often fails. It is crucial that the correct exit code is passed on.

This code works as expected:

#!/usr/bin/env bash

function my_function {
    echo "Important output"
    exit 1
}

function cleanup {
  MY_EXIT_CODE=$?
  echo "MY_EXIT_CODE: ${MY_EXIT_CODE}"
}

trap cleanup EXIT

my_function

MY_EXIT_CODE is 1 as expected and running echo $? after the script gives me 1 as well (as expected)

However, I need to get the complete output of my_function both to a variable and the console output. In order to do so, as advised in this answer (which seems itself based on this answer) I changed my code into

#!/usr/bin/env bash

function my_function {
    echo "Important output"
    exit 1
}

function cleanup {
  MY_EXIT_CODE=$?
  echo "MY_EXIT_CODE: ${MY_EXIT_CODE}"
}

trap cleanup EXIT

exec 5>&1
FF=$(my_function|tee /dev/fd/5)

And now the exit code is wrong. Is it 0 while it should be 1. I know this is somewhat connected to subshell handling but I couldn't figure out how to solve it.


Solution

  • And now the exit code is wrong. Is it 0 while it should be 1

    No, your assumption is wrong. Assuming tee succeeded, the exit code should be 0. From the posix shell manual:

    If the reserved word ! does not precede the pipeline, the exit status shall be the exit status of the last command specified in the pipeline.

    The "last command" in a pipeline is the rightmost command. Because in your case tee exits with 0, the exit status of FF=$(.... | tee) is zero.

    how to solve it.

    That depends on the behavior you want to achieve. Usually, in bash you may just set -o pipefail to always catch errors.