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
两种选择:
pipefail
从 ksh ( )设置该选项set -o pipefail
,则管道的退出状态将是最右侧失败的管道组件的退出状态。set -o pipefail if ! A | B | C; then echo at least one of the commands failed. fi
查找 中的非零值
$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