'Combining mapfile, command redirection and exit status retrieval

I am reading a build command as so:

mapfile -t make_out < <(2>&1 ./make.sh my_program)

I would like to print the output kept in make_out only if the build failed. How would I both keep the exit status, and save the output for later use (respecting spacing, newlines, and in general safe parsing)?

I am open to changing the way I read the results, but I do not want solutions saving stuff in an extra file or relying on analyzing the text. It is valid if this cannot be done.



Solution 1:[1]

You can enable lastpipe option and turn the command into a pipeline; so that mapfile is run in the current execution environment, and ./make.sh's exit status can be retrieved from PIPESTATUS array.

# call set +m first if job control is enabled
shopt -s lastpipe
./make.sh my_program 2>&1 | mapfile -t make_out
if [[ PIPESTATUS[0] -ne 0 ]]; then
  printf '%s\n' "${make_out[@]}"
fi
# revert changes to shell options if necessary

Solution 2:[2]

Something along the lines is what I came up with lately. In short, supply the exit code as the last array element and carve it out:

mapfile -t make_out < <(2>&1 ./make.sh my_program; echo ${?})

declare -ir exit_code=${make_out[-1]}
unset make_out[-1]

if ((exit_code != 0))
then
        printf '%s\n' "${make_out[@]}"
fi

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Superlexx