grep --quietの終了状態に問題がありますか?

grep --quietの終了状態に問題がありますか?

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パイプの戻り値141pipefail

実際に使用すると仮定すると、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 …)echoechoシェルが組み込まれている可能性が高いので、「それ」がSIGPIPEを受信すると、実際にはSIGPIPEを受信して​​終了する完全なサブシェルです。私たちは実行しなければならないサブシェルをtrue終了させたくありません。はじめにこの回答

スクリプト全体を確認してください。他の条件も同じ方法で問題を引き起こす可能性があります。

関連情報