How to get both PIPESTATUS and output in bash script
You could do this:
TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )
Then $?
will be the return code from ls
. This doesn't work if you need the return code from more than one of the pipe parts (but you could split the pipeline if the output isn't too large, as it is here).
Here's a rather expensive way of getting the full PIPESTATUS
array and the output. Not very elegant, but haven't found anything else:
result=$(echo -e "a\nb\nc" | \
( cat ; exit 1 ) | \
( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"
Which gives:
Output:
a
b
c
Results:
0 1 42
Use set -o pipefail
in bash
to get the right-most non-zero exit code in a piped command sequence as $?
. From man bash
:
If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.
Then you can simply access $?
. Use set +o pipefail
to disable again.
I assume the issue here is that PIPESTATUS goes away in its entirety as soon as you execute a command. You can get the complete PIPESTATUS array in bash version 2 or above this way:
declare -a status
status=(${PIPESTATUS[@]})
Then access ${status[0]}
, ${status[1]}
, etc.
The main problem with "what you expect" is that a command in backquotes is executed in a subshell; $PIPESTATUS
exists there and the status returned fromm it follows the same rules as if you executed a single executable (or shell script). The status of the backquote command is the rightmost (awk
) status.
To implement what @Daniel Beck said, set the pipefail
option in the subshell thusly:
TM_LOCAL=`set -o pipefail; ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'`
now the status stored in $?
afterwards will be the status of ls
(if non-zero).
However, I think an explicit if [ -f ~/.vimrc ];
... test would be more readable.
You can't get output into a variable and PIPESTATUS
returned without either a temporary file for the former, or marshalling the latter into a string.