シェルスクリプトを使用して実行されたコマンドが失敗するたびに失敗したいと思います。
通常私はこうする:
set -e
set -o pipefail
(通常私もset -u
そう追加します)
問題は、上記の方法のいずれもプロセスの交換には効果がないことです。このコードは "ok" を印刷し、戻りコード = 0 で終了します。一方、私は失敗したいと思います。
#!/bin/bash -e
set -o pipefail
cat <(false) <(echo ok)
プロセスの交換に加えて、「パイプの失敗」に対応するものはありますか?コマンドの出力をファイルに渡しますが、これらのプログラムが失敗するたびにエラーを発生させる別の方法はありますか?
貧しい人々の解決策は、これらのコマンドがstderrに書き込まれるかどうかを検出することです(ただし、一部のコマンドは成功した場合はstderrに書き込みます)。
別のposix互換ソリューションは名前付きパイプを使用することですが、コンパイルされたコードから動的に構築された単一のライナーでプロセス置換を使用してそのコマンドを開始する必要があり、名前付きパイプを作成すると作業が複雑になります(追加のコマンド、エラー捕獲)。削除など)
ベストアンサー1
この問題は、次の方法でのみ解決できます。
cat <(false || kill $$) <(echo ok)
other_command
SIGTERM
スクリプトのサブシェルは、2番目のコマンドを実行する前に()を完了しますother_command
。コマンドはecho ok
「時々」実行されます。問題は、プロセスの交換が非同期であることです。kill $$
命令が実行されるという保証はありません。今後または後ろに注文するecho ok
。これはオペレーティングシステムのスケジューリングの問題です。
次のbashスクリプトを考えてみましょう。
#!/bin/bash
set -e
set -o pipefail
cat <(echo pre) <(false || kill $$) <(echo post)
echo "you will never see this"
このスクリプトの出力は次のとおりです。
$ ./script
Terminated
$ echo $?
143 # it's 128 + 15 (signal number of SIGTERM)
または:
$ ./script
Terminated
$ pre
post
$ echo $?
143
試してみてください。数回試行すると、出力に2つの異なる順序が表示されます。最初のコマンドでは、echo
他の2つのコマンドがファイル記述子に書き込む前にスクリプトが終了します。 2番目のコマンドでは、false
またはkill
コマンドをecho
コマンドの後に予約できます。
あるいは、より正確には、シェルプロセスにシグナルを送信するユーティリティのシステムコールは、signal()
echoシステムコールより遅くまたは早く予約(または転送)されます。kill
SIGTERM
write()
ただし、スクリプトが停止し、終了コードがゼロではありません。だからそれはあなたの問題を解決する必要があります。
別のソリューションもちろん、これには名前付きパイプを使用します。ただし、名前付きパイプまたは上記の回避策を実装するスクリプトがどれほど複雑かによって異なります。
引用: