
zsh
スクリプトには長いコマンドパイプラインがあります。
pv /dev/sda > sda.raw | sha256sum > sda.raw.sha256 | cut -c61-64 | read SHASUM
if
すべてのコマンドが正常に終了したかどうか、ステートメント内でどのように確認できますか?
わかりました${pipestatus[@]}
。しかし、配列です。したがって、各要素を個別に確認する必要があります。
${pipestatus[@]}
含まれている内容だけを確認するショートカットはありますか0
?
修正する:
いくつかの奇妙な動作を発見しました。
テスト用にすばやく埋めるように小さなファイルシステム(10 MB)を設定しました。
#!/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
2つのオプション:
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