grep バージョン 2.16 がインストールされている SLES 12 SP5 システムがあり、1 つのシステムでは、grep --quiet
次の条件を含むスクリプトを大量に使用します。
# $pid_list contains the result of pstree and $script_pid equals $$
if echo "$pid_list" | grep -qF "($script_pid)"; then
continue
fi
if echo "$pid_list" | grep -qF "($script_pid)"; then
echo "Error: grep has a bug!"
continue
fi
最初の条件が失敗する確率は約0.1%で、2番目の同じ条件が成功する確率は2倍になりますか? !
次のように条件を変更すると完全に機能します(フルコードここ):
if echo "$pid_list" | grep -F "($script_pid)" >/dev/null; then
continue
fi
マニュアルに関しては、このquiet
オプションは期待どおりに機能するはずです。エラーが発生した場合はtrueを返す必要があります。
一致するものが見つかると、エラーが検出された場合でも状態0で直ちに終了します。
それで、なぜ失敗するのか混乱しています。マシンのRAMとファイルシステムの両方が正常です。 grepバイナリにも正しいファイルハッシュがあります。
私検索を送信しかし、私が見つけた唯一のこと2001年から、これは次の一部でなければなりません。2.16 2014年から。
アップデート1
@kamilが提案したようにサブシェルを試してみましたが、それでも失敗します(時には「競合条件」エラーが表示されます)。
if (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
continue
elif (echo "$pid_list"; true) | grep -qF "($script_pid)"; then
echo "Error: Race condition!"
continue
fi
代わりに、次のように動作します。
if echo "$pid_list" | grep -qF "($script_pid)" || [[ $? -eq 141 ]]; then
continue
fi
答え1
前提:実行するスクリプトでset -o pipefail
(スクリプトを解釈するシェルがBashの場合、他のシェルも同様の機能を提供できます)。からman 1 bash
:
pipefail
設定されている場合、パイプラインの戻り値は、ゼロ以外の状態で終了した最後の(最も右側の)コマンドの値、またはパイプラインのすべてのコマンドが正常に終了した場合は0です。このオプションはデフォルトで無効になっています。
一致するものがあれば、grep -q
早く終了して戻ります0
。それからecho
戻ってくるかもしれないし、戻らないかもしれない141
。これはecho
、パイプの終わりを閉じる前にパイプバッファにすべてを書き込むことができるかどうかによって異なります。grep
同じ入力でも、状況はいろいろな方法で進むことができます。競争条件。これが発生した場合、141
パイプの戻り値141
はpipefail
。
実際に使用すると仮定すると、set -o pipefail
観察される動作は確かにgrep
シェルの欠陥ではありません。エラーはスクリプトにあります。
リンクされた質問に対する私の答えは解決策を提供します。最も簡単な方法は次のとおりです。
if (/bin/echo "$pid_list"; true) | grep -qF "($script_pid)"; then
または
if ((echo "$pid_list"); true) | grep -qF "($script_pid)"; then
なぜか/bin/echo …
代わり(echo …)
にecho
?echo
シェルが組み込まれている可能性が高いので、「それ」がSIGPIPEを受信すると、実際にはSIGPIPEを受信して終了する完全なサブシェルです。私たちは実行しなければならないサブシェルをtrue
終了させたくありません。はじめにこの回答。
スクリプト全体を確認してください。他の条件も同じ方法で問題を引き起こす可能性があります。