Discussion:
Trouble with PIPESTATUS
(too old to reply)
l***@gmail.com
2015-11-02 18:38:12 UTC
Permalink
Greetings,

I'm having trouble getting the PIPESTATUS with the following code:

set -o pipefail
declare -a DIRLIST
DIRLST=$(ls -lda /tmp/foo/* | grep ^d | awk '{print $9}')
echo "0: ${PIPESTATUS[0]} 1: ${PIPESTATUS[1]} 2: ${PIPESTATUS[2]}"
#
if [ ${PIPESTATUS[0]} -eq 0 ] && [ ${PIPESTATUS[1]} -eq 0 ] && [ ${PIPESTATUS[2]} -eq "0" ]; then
echo "Direcotry List Good."
else
echo "Directory List Bad"
fi

Only PIPESATUS[0] is getting set. Any ideas what I'm doing wrong here?

Thanks in advance for any help.

Tom
Stephane Chazelas
2015-11-02 21:16:15 UTC
Permalink
Post by l***@gmail.com
Greetings,
set -o pipefail
declare -a DIRLIST
DIRLST=$(ls -lda /tmp/foo/* | grep ^d | awk '{print $9}')
echo "0: ${PIPESTATUS[0]} 1: ${PIPESTATUS[1]} 2: ${PIPESTATUS[2]}"
#
if [ ${PIPESTATUS[0]} -eq 0 ] && [ ${PIPESTATUS[1]} -eq 0 ] && [ ${PIPESTATUS[2]} -eq "0" ]; then
echo "Direcotry List Good."
else
echo "Directory List Bad"
fi
Only PIPESATUS[0] is getting set. Any ideas what I'm doing wrong here?
[...]

Yes PIPESTATUS doesn't work with $(...) and it's the same with
the equivalent $pipestatus in zsh. The reason is from
implementation.

In

a=$(foo | bar)

A sub-shell is created to run that pipeline, and all the
information the parent shell gets is the exit status of that
subshell which it gets by doing a waitpid() on the subshell
process. The subshell does get the exit status of each command
in the pipeline but has no way to send it back to the parent.

In order to be able to do that, the shell would have to set up
some inter-process communication channel between parent and
subshell and a protocol to send that information. But it doesn't
do it.

Not much you can do about it.

In this case though, you could test for DIRLST being the empty
string. As if it was empty, that would mean at least grep would
have failed. And if any of those command fails, the output would
typically be empty.

Note that

DIRLST=$(ls -lda /tmp/foo/* | grep ^d | awk '{print $9}')

is wrong in the general case as it assumes filenames and user
and group names don't contain blanks or newlines.

With zsh, you'd do:

dirlst=(/tmp/foo/*(N/))
--
Stephane
Loading...