In bash 5.0, I wish to capture the
${PIPESTATUS[@]}
of a piped command that is executed via eval
. However, eval
appears to mask ${PIPESTATUS[@]}
, but doesn't mask $?
which is the equivalent to ${PIPESTATUS[-1]}
. Is there a way to extract ${PIPESTATUS[@]}
from the results of eval
? Appending something to the commandstring below like && array=( ${PIPESTATUS[@]} ) && export array
does not appear to work.
Am I correct in assuming from this that $?
is not simply ${PIPESTATUS[-1]}
?
My sample code (ran as root):
#!/usr/bin/env bash
#without eval, ${PIPESTATUS[@]} has two entries as it should.
apt-get install -y java-17-openjdk-amd64 2>&1 | tee -a ~/log
commandsPipestatus=( ${PIPESTATUS[@]} )
for status in ${commandsPipestatus[@]}; do
echo $status
done
echo ""
echo ""
#with eval, ${PIPESTATUS[@]} has one entry and is equal to $?
commandstring="apt-get install -y java-17-openjdk-amd64 2>&1 | tee -a ~/log"
eval "$commandstring"
commandsPipestatus=( ${PIPESTATUS[@]} )
for status in ${commandsPipestatus[@]}; do
echo $status
done
EDIT: Fixed a small technical correction in my original statement about PIPESTATUS. Also, based on the answers below, here are some clarifications:
- I'm using eval
because I'm building command strings programmatically and some of them may contain bash -c
... which run the command as different users.
- I looked at setting pipefail
and that may work sometimes though not always because sometimes I need to know the status of multiple steps in the pipe. If I could set set -o pipefail
and then unset it after that could work, but I'm not seeing how to unset pipefail
and I can't simply exit the subshell and then continue in a new one where pipefail
is not been set. How do I unset a shell option such as pipefail
?
- Is my above understanding of how to export an array that contains PIPESTATUS
incorrect? How can I simply export PIPESTATUS
from the eval
subshell?
EDIT 2: Thanks to the excellent answer marked below, my final decision was for the case where I am dynamically assembling command strings that include redirection (which is why I need eval), I would use set -o pipefail
and then after execution do set +o pipefail
.
I'm also re-researching best practices for executing dynamically built commands, as I have several years more bash experience since the last time I did. My use cases for eval
are:
1. Commands may contain bash -c
, so I can't use bash -c
to execute them
2. May contain redirection, such as >> log
3. The dynamical commands may also have arguments added to them for debugging purposes
As far as I can tell, I may be able to do things differently for 1, and for 3 I should be using things like set -x [command]
and trap
instead. I have yet to find a solution for 2.
Asked by jitter
(5 rep)
Oct 15, 2023, 06:29 AM
Last activity: Oct 23, 2023, 06:47 AM
Last activity: Oct 23, 2023, 06:47 AM