照会出力を制限し、信号13を防止します。

照会出力を制限し、信号13を防止します。

特定のパターンを検索するために必要な約1Mファイルを含むディレクトリがあります。私はすべてのファイルに対してこれを行う方法を知っています。

find /path/ -exec grep -H -m 1 'pattern' \{\} \;

完全な出力は必要ありません(遅すぎます)。最初の数回クリックすると効果があったので、行数を制限してみました。

find /path/ -exec grep -H -m 1 'pattern' \{\} \; | head -n 5

これにより5本の線が生成され、次に

find: `grep' terminated by signal 13

そしてfind働き続けなさい。これは説明しやすいです。ここ。私はquit行動を試みました:

find /path/ -exec grep -H -m 1 'pattern' \{\} \; -quit

これは最初の一致のみを出力します。

検索出力を特定の数の結果に制限できますか(例:quitsimple toに似たパラメータを提供head -n)。

答え1

-quitすでにGNU拡張(、、、-H)を使用しているので、GNUオプションを使用して一致を見つけるとすぐに出力すること-m1もできます。したがって、一致が見つかると、SIGPIPEによって終了される可能性が高くなります。 6行目は次のとおりです。grep-r--line-buffered

grep -rHm1 --line-buffered pattern /path | head -n 5

の場合、find次のことが必要になる場合があります。

find /path -type f -exec sh -c '
  grep -Hm1 --line-buffered pattern "$@"
  [ "$(kill -l "$?")" = PIPE ] && kill -s PIPE "$PPID"
  ' sh {} + | head -n 5

つまり、ラップしてgrep(まだ可能な限り少ない呼び出しをsh実行したいので、はい)、SIGPIPEのために終了したら、その親()を終了します。grep{} +shfindgrep

別のアプローチは、生成されたコマンドが信号のために終了したときにすぐにxargsas.exitを使用することです-exec {} +xargs

 find . -type f -print0 |
   xargs -r0 grep -Hm1 --line-buffered pattern |
   head -n 5

-rそして-0GNU拡張です)。grep破損したパイプへの書き込みが行われると、両方が終了し、grep次に何かが印刷されたときにもそれ自体が終了します。走ると、より早く起こります。xargsfindfindstdbuf -oL

POSIXのバージョンは次のとおりです。

trap - PIPE # restore default SIGPIPE handler in case it was disabled
RE=pattern find /path -type f -exec sh -c '
  for file do
    awk '\''
      $0 ~ ENVIRON["RE"] {
        print FILENAME ": " $0
        exit
      }'\'' < "$file"
    if [ "$(kill -l "$?")" = PIPE ]; then
      kill -s PIPE "$PPID"
      exit
    fi
  done' sh {} + | head -n 5

ファイルごとに複数のコマンドを実行するため、非常に非効率的です。

答え2

エラーを防ぐための解決策は次のとおりです。

find / -type f -print0 \
  | xargs -0 -L 1 grep -H -m 1 --line-buffered 2>/dev/null \
  | head -10

この例では、コマンドが失敗するとxargsが停止するため、パイプエラーのみが発生し、これはstderrリダイレクトによってフィルタリングされます。

答え3

grep一度に1つのファイルを操作します。あなたのものを使用すると、-quit最初の成功したgrepで検索を停止できます。

[更新]私の最初の解決策は、一度に複数のファイルをgrepすることでした。

find /path/ -type f -exec grep -H -m 1 'pattern' \{\} + -quit | head -n 5

(魔法は、サブコマンドの末尾に.を追加することです+。/ path /に複数のファイルが含まれていると確信している場合は、このオプションを削除できます)-exec-type f-Hgrep

@StéphaneChazelasが報告したように、問題は-execコマンドが非同期で実行され、常に最初のファイルでtrue=>終了を返すことです。find

完了時に停止するには、受信find中のSIGPIPEも受信する必要があります(信号13)。これは、パイプを介して何かを転送する必要があることを意味します。headfindgrepfind

以下は、Stéphaneの提案に基づいて改善された迅速で汚いトリックです。

find /path/ -type f -exec grep -H -m 1 --line-buffered 'pattern' {} + -printf '\r' | head -n 5

出力を無害な文字に-printf '\r'強制すると、出力が変わらないことを願っています。停止すると、SIGPIPEが受信され停止します。findgrepheadfind

[更新2]私はこれが汚いハッキングだと警告しました。より良い解決策は次のとおりです。

find /path/ -type f -exec grep --quiet 'pattern' {} ";" -print | head -n 5

ここではもうgrepファイル名を印刷しませんが、find=>「grepはシグナル13で終了しました」findで終わりませんhead。問題は、一致する行が印刷されなくなることですgrep

[update3] 最後に、@Andreyが提案したように、以下の恥ずかしくて醜いコマンドは最後の問題を解決します。

find /path/ -type f \
    -exec grep --quiet 'pattern' {} \; \
    -printf '%p:' \
    -exec grep -h -m 1 'pattern' {} \; \
| head -n 5`

答え4

より簡単な場合、代替パスはパイプではなく文字列にすることができます。たとえば -

find . -exec stat -c %y {} \; | head -n1

上記のような問題を見るでしょう。考慮する簡単な方法 -

head -n1 <<<$(find . -exec stat -c %y {} \;)

関連情報