1

I have long pipeline of commands in zsh script:

pv /dev/sda > sda.raw | sha256sum > sda.raw.sha256 | cut -c61-64 | read SHASUM

how can I check inside an if statement, that all commands exited successfully?

I know about ${pipestatus[@]}, but it is an array. So I would have to check each element individually.

Is there some shortcut to check that ${pipestatus[@]} contains only 0 ?

UPDATE:

I have discovered some weird behavior:

for testing, I set up small filesystem (10MB) so that it fills up quickly:

#!/bin/zsh

set -o pipefail

if pv /dev/zero > loop/file ; then
echo OK
else
echo FAIL
fi

as expected, I get following error, and "FAIL" printed:

pv: write failed: No space left on device

However, when I change the pv command just slightly, it suddenly does not print any error, and the pv command seems to run indefinitely (even though there is no space left on the device)

#!/bin/zsh

set -o pipefail

if pv /dev/zero > loop/file | sha256sum ; then
echo OK
else
echo FAIL
fi
5
  • Set pipefail and check $??
    – muru
    Oct 3 at 3:23
  • A comment about the pipeline you show: pv seems to write to a file via a redirection, meaning sha256sum won't ever get anything to process. Likewise, the output of sha256sum is redirected to a file, so even if it produced output, cut would never get anything to work with. Consequently, the final read won't do anything as all the data is written to files instead of to the next stage of the pipeline. If the redirections are removed, the read might read something into the SHASUM variable, but this is not what our question is about.
    – Kusalananda
    Oct 3 at 7:43
  • @Kusalananda - I think this works in zsh when you enable the multios option Oct 3 at 8:23
  • So it does (sorry for not using my brain). Still, it would be better, for the readability of the question, if the reliance on this feature was either pointed out explicitly or removed in the question.
    – Kusalananda
    Oct 3 at 9:14
  • 2
    Your update is a side effect of multios, and it should be asked as a separate question (pv doesn't fail there, so of course there's no failure to detect and so it's a completely different problem than the original question).
    – muru
    Oct 3 at 14:57

1 Answer 1

2

Two options:

  1. set the pipefail option from ksh (set -o pipefail), then the exit status of a pipeline will be that of the right-most pipeline component that failed.

    set -o pipefail
    if ! A | B | C; then
      echo at least one of the commands failed.
    fi
    
  2. look for non-zero values in $pipestatus. With the extendedglob option enabled, $pipestatus[(r)^0] (or $pipestatus[(r)<1->] which doesn't require extendedglob) will return the exit status of the left-most failing pipeline component and $pipestatus[(R)^0] of the right-most, so you can do:

    set -o extendedglob
    A | B | C
    if (( $pipestatus[(r)^0] )); then
      echo at least one of the commands failed.
    fi
    

    or

    A | B | C
    if (( $pipestatus[(r)<1->] )); then
      echo at least one of the commands failed.
    fi
    

    With the I subscript flag instead of r/R, you'll get the Index of the right-most matching element, so you can do:

    A | B | C
    if (( failed = $pipestatus[(I)<1->] )); then
      echo component $failed failed.
    fi
    

    ${pipestatus:#0} will expand to the components of $pipestatus except 0, so you could also do:

    A | B | C
    failed_statuses=( ${pipestatus:#0} )
    if (( $#failed_statuses )); then
      echo "${#failed_statuses} command(s) failed. Statuses: $failed_statuses"
    fi
    
2
  • this does not seem to work. Could you please look at my updated question? Oct 3 at 14:55
  • @MartinVegter, see muru's comment to your question. With pv > file | cmd, since you're redirecting pv's output several times, pv's stdout is not a pipe to a teeing process, not to cmd. And that teeing process doesn't die when one of the destinations cannot be written. Same as in cat /dev/zero > /dev/full > /dev/null Oct 3 at 15:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .