web-dev-qa-db-ja.com

最初の一致後に検索コマンドを停止する方法は?

最初の一致を見つけた直後にfindコマンドを強制的に停止する方法はありますか?

138
coffeMug

GNUまたはFreeBSD findを使用すると、-quit述語を使用できます。

find . ... -print -quit

同等のNetBSD find

find . ... -print -exit

名前を印刷するだけで、ファイル名に改行文字が含まれていないと想定すると、次のようにできます。

find . ... -print | head -n 1

最初の一致の後でfindが停止することはありませんが、2番目の一致時または(かなり)後のタイミングとバッファリングに応じて可能性があります。基本的に、findは、入力の最初の行を既に読み取って表示しているため、headがすでになくなっている間に何かを出力しようとすると、SIGPIPEで終了します。

findが返された後、すべてのシェルがそのheadコマンドを待機するわけではないことに注意してください。 Bourne ShellおよびAT&Tのksh(非対話型の場合)とyash(そのパイプラインがスクリプトの最後のコマンドの場合のみ)の実装では、バックグラウンドで実行されたままになります。シェルでその動作を確認したい場合は、常に上記を次のように変更できます。

(find . ... -print &) | head -n 1

見つかったファイルのパスを出力するだけではない場合は、次の方法を試すことができます。

find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;

printfを、そのファイルで実行することになるものに置き換えます)。

これには、findが強制終了されたという事実を反映して終了ステータスを返すという副作用があります。

実際には、SIGTERMの代わりにSIGPIPEシグナル(killの代わりにkill -s PIPE)を使用すると、一部のシェルがその死についてより静かになります(ただし、ゼロ以外の終了ステータスが返されます)。

156
find . -name something -print -quit

印刷後、最初の一致後にfindを終了します。

特定の数の一致の後にfindを終了し、結果を印刷します。

find . -name something -print | head -n 5

意外にも十分です。方法や理由はわかりませんが、headは5回一致した後に文字列を終了します。

テストは非常に簡単です。ルートで検索aを見つけさせてください。少なくとも1分以上かかりますが、数千、場合によってはさらに多くの一致が得られます。ただし、「head」にパイプすると、「find」は指定した量のlinesがヘッドで定義された後に終了します(デフォルトのヘッドは10を示し、「head -n」を使用してラインを指定します)。

これは、「head -n」が指定された改行文字数に達した後に終了するため、複数の改行文字を含むすべての一致がそれに応じて数えられることに注意してください。

12
TheUnseen

エンターテインメントの目的で、Bashの遅延検索ジェネレータを次に示します。この例では、現在のディレクトリのファイルにリングを生成します。好きなだけ読んでくださいkill %+(たぶん1)

#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT

coproc x while :; do
    find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
    read -r _
    printf '%s\0' "$x"
done
EOF

while
    echo >&${x[1]}
    IFS= read -rd '' -u "$x" 'files[n++]'
do
    printf '%q ' "${files[@]}"
    echo
    sleep .2
done
2
ormaaj

フラグ-mと一緒に使用すると、grepも返されるため、

find stuff | grep -m1 .

findによって出力された最初の行の後に戻ります。

これとfind stuff -print -quit | head -1の違いは、検索が十分に高速である場合、grepは時間内にプロセスを停止できない可能性があります(実際には問題ではありません)。多くの不要な行。

これは代わりにbusybox findで機能しますが、busybox grepにも-mがあるため、実際には必要ありません

find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;

これは、(通常)sigtermシグナルを受信したfindプロセスに関するメッセージを吐き出しますが、この出力は、findコマンドではなく、実行中のシェルに属しているため、コマンド出力に干渉しません。つまり、パイプまたはリダイレクトは行のみを出力します検索で一致。

1
untore