更新:

更新:

zsh我在脚本中有很长的命令管道:

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

如何在if语句内部检查所有命令是否成功退出?

我知道${pipestatus[@]},但它是一个数组。所以我必须单独检查每个元素。

是否有一些快捷方式可以检查${pipestatus[@]}仅包含0

更新:

我发现了一些奇怪的行为:

为了进行测试,我设置了小型文件系统(10MB),以便它很快填满:

#!/bin/zsh

set -o pipefail

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

正如预期的那样,我收到以下错误,并打印“FAIL”:

pv: write failed: No space left on device

但是,当我稍微更改 pv 命令时,它突然不会打印任何错误,并且 pv 命令似乎无限期地运行(即使设备上没有剩余空间)

#!/bin/zsh

set -o pipefail

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

答案1

两种选择:

  1. pipefail从 ksh ( )设置该选项set -o pipefail,则管道的退出状态将是最右侧失败的管道组件的退出状态。

    set -o pipefail
    if ! A | B | C; then
      echo at least one of the commands failed.
    fi
    
  2. 查找 中的非零值$pipestatus。启用该extendedglob选项后,$pipestatus[(r)^0](或$pipestatus[(r)<1->]不需要extendedglob)将返回最左侧失败管道组件和$pipestatus[(R)^0]最右侧失败管道组件的退出状态,因此您可以执行以下操作:

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

    或者

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

    使用I下标标志而不是r/ R,您将获得I最右侧匹配元素的索引,因此您可以执行以下操作:

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

    ${pipestatus:#0}将扩展到除 0 之外的组件$pipestatus,因此您也可以这样做:

    A | B | C
    failed_statuses=( ${pipestatus:#0} )
    if (( $#failed_statuses )); then
      echo "${#failed_statuses} command(s) failed. Statuses: $failed_statuses"
    fi
    

相关内容