Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipe status after command substitution

Tags:

bash

pipe

I'd like to send the result of a series of commands to a variable:

variable=$(a | few | commands)

However, the command substitution resets PIPESTATUS, so I can't inspect where it went wrong after the fact. One solution would be to use mktemp and put the result there temporarily:

variable_file=$(mktemp) || exit 1
a | few | commands > $variable_file
exit_codes="${PIPESTATUS[*]}"
variable=$(<$variable_file)

Is there a more elegant solution?

like image 292
l0b0 Avatar asked Dec 10 '10 15:12

l0b0


2 Answers

Kinda hacky but I think you could fudge it like this.

variable=$(a | few | commands; echo ": ${PIPESTATUS[*]}")
PIPESTATUS=(${variable##*: })
variable=${variable%:*}
variable=${variable%$'\n'}
like image 198
ephemient Avatar answered Oct 12 '22 20:10

ephemient


Building on ephemient's answer, if we need the output of the piped commands stored without them being mixed in with the pipestatus codes, but we don't really care what the exit codes themselves are (just that they all succeeded), we can do:

variable=$(a | few | commands; [[ ${PIPESTATUS[*]} == "0 0 0" ]])

This will check on the status of all the piped command status in the above example and if its exit code is not 0, will set $? to 1 (false)

If you want to exit with a different code instead of 1, you could capture the contents of PIPESTATUS[#], e.g. r_code=${PIPESTATUS[2]}, and then use (exit ${r_code[2]}) instead of false.

Below captures all the codes of PIPESTATUS, ensures they're all 0, and if not, sets the exit code to be the $? value of commands:

declare -a r_code 
variable=$(a | few | commands
           r_code=(${PIPESTATUS[@]})
           [[ ${r_code[*]} == "0 0 0" ]] || (exit ${r_code[2]})
)

echo ${?}         # echoes the exit code of `commands`
echo ${variable}  # echoes only the output of a | few | commands
like image 22
Jon Avatar answered Oct 12 '22 20:10

Jon