以下を考慮してください。
command1 | command2 | command3
私が理解したように、パイプラインは発生する可能性のあるエラーに関係なくすべてのコマンドを実行します。コマンドがstderrを返すと、次のコマンドにパイプされませんが、次のコマンドは引き続き実行されます(|&
使用しない限り)。発生する可能性のあるエラーがある場合は、残りのパイプラインを終了したいと思います。私はこれを達成することが可能だと思いますset -o pipefail
が、パイプのどんなものでも失敗した場合、パイプの後ろに来ることができるすべてを終了します。つまり:
(set -o pipefail; cmd1 | cmd2 && echo "I won't run if any of the previous commands fail")
したがって、終了する最も簡単な方法は残りコマンドが失敗した場合、パイプラインはどうなりますか?また、失敗したコマンドに対して正しいstderrを使用して終了する必要があります。私はシェルスクリプトではなくコマンドラインコンテキストでこれを行うので、単純さを探しています。アイデア?
答え1
私はこれが不可能だと信じています
私はあなたが要求することがパイプの実装方法のために直接可能ではないと思います。シェルがパイプラインで「後で」コマンドを実行すると、コマンドの成功または失敗(戻り値)がわかりません。実際にはすべて同時に実行し、結果を収集します。
役に立つかもしれないいくつかの回避策があります。
ソリューション1
一度に 1 つのコマンドを実行し、結果をキャッシュします。 前のコマンドが失敗した場合、それ以降のコマンドは実行されないため、これがより良いです。
非常に短いスクリプトの例:
cache_file=`tempfile`
if command1 > $cache_file ; then
command2 < $cache_file
fi
rm $cache_file
ソリューション2
すべてを実行し、戻り結果を確認してください。 とにかくこれを行うと、すべてのコマンドが実行されますが、戻って理由を見つけることができます。
ここで、各コマンドのSTDERRは拡張子です2>
。PIPESTATUS
各コマンドの戻りコードを見つけるには、確認してください。
command1 2> command1_err.log | command2 2> command2_err.log
for result in ${PIPESTATUS[@]} ; do
if [ $result -ne 0 ] ; then
echo command failed
fi
done
シェルでパイプラインを実行するための簡単な概要
パイプを作成するために、シェルは次の手順に従います。〜のようにこれら:
- 次のコマンド(
|
)を使用して各パイプを作成します。管路()。各パイプには読み取りハンドルと書き込みハンドルがあります。各リダイレクト(<
、、>
)に対してそのファイルを開き、それを使用してファイルへのハンドルを取得します。開いている()。 - シェル呼び出しクロス()パイプラインの各コマンドは新しいプロセスを開始します。
- 各サブプロセスは、(1.)で生成されたハンドルとSTDIN、STDOUT、およびSTDERRハンドルを交換します。
- コマンドが外部バイナリであると仮定すると、各子プロセスは以下を呼び出します。実装する()バイナリをロードして実行します。
- その後、親プロセスは子プロセスが使用を終了するのを待ちます。待つ()また、コマンドの戻り値(成功または失敗)も提供します。
答え2
パイプラインを停止するきちんとした方法は、途中でシェルを終了することです。これはインタラクティブシェルを終了することを意味するので(ターミナルエミュレータで実行している場合)、作業を続行するには別のシェルを起動する必要があります。ただし、これにより、少なくとも次のパイプラインコマンドが停止します。
command1 2> command1_error.log | awk -v status=$? -v pid=$$ '{if (status != 0) { system("kill -9 " pid) } else { print } }' | command2 ..
注:ターミナル/ ttyでこのコマンドを実行すると、ログアウトされます。
または、最後のコマンドをブロックしたい場合(たとえば、ファイルを生成するコマンドがパイプラインの最後のコマンド)、次のように使用できます。xargs -r
command1 | command2 | xargs -r command3
このフラグは、前のコマンドが何も出力しなかった場合に-r
command3が実行されるのを防ぎます。xargs