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


131

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


4
TheUnseen:ヘッド-n 5にパイプされたときに5つの結果の後に終了する理由は、5つの結果の後にヘッドが終了するためです。headが終了すると、パイプが閉じ、プログラムにパイプを送り、同様に終了します。直接返信しないで申し訳ありませんが、返信するには50の評判が必要なようです。
ルステ

回答:


148

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

find . ... -print -quit

find同等のNetBSD :

find . ... -print -exit

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

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

それはfind最初のマッチの後に停止しませんが、おそらく、2回目のマッチのタイミングとバッファリングに応じて、または(ずっと)後になります。基本的に、入力の最初の行をすでに読み取って表示しているので、既になくなっているfind間に何かを出力しようとすると、SIGPIPEで終了しheadます。

すべてのシェルが戻ったfind後にそのコマンドを待つわけではないことに注意してくださいhead。Bourneシェルおよび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 -s PIPE代わりにすることはkill)一部のシェルは、その死についてもっと静かにさせるだろう(まだゼロ以外の終了ステータスを返します)。


3
誰かがファイルが述語と一致するかどうかをテストする必要がある場合、見つかったらすぐに停止します。BashとGNU Findでできることはif [[ $(find ... -print -quit) ]]; then ...、印刷されたものを見つけるかどうかだけです。
トビア14

@Tobia $(…)単一の角かっこ([ … ])のみを使用している場合に備えて、引用符で囲んだ方が良いでしょう。
phk

@phk私は単一の括弧を使用していないことを除いて(それらは恐ろしいため)、引用符を使用する必要はありません。
トビア

2
@Tobia [は標準コマンドです。恐ろしいのはコマンドではなく、Bourneのようなシェルがコマンドラインを解析する方法です。[[...]]さまざまなシェルに独自の問題があるkshコンストラクトです。たとえば、最近まで[[ $(...) ]]動作しませんでしたzsh(必要です[[ -n $(...) ]])。除いてzsh、あなたが引用符を必要とし[[ $a = $b ]][[ =~ ]]実装の間、さらにいくつかの中のbash用のバージョンと互換性のないいくつかのバグとの間に違いがあります。個人的に、私は好む[
ステファンシャゼル

なに...?。
kyb

11
find . -name something -print -quit

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

特定の量の一致後に検索を終了し、結果を出力します。

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

驚くべきことに-headは5回の一致の後に文字列を終了させるようになりましたが、方法や理由はわかりません。

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

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


また、この「プログラムは、ヘッドが出力を完了した後に終了する」現象を観察しましたが、シェル間で一貫していません。これはそれ自身の質問に値すると思います-幸いなことに、bashの答えは既にStackOverflowのBash:bash scriptでのHead&Tailの動作にあります。これにより、プログラムがバックグラウンドで終了するか実行を継続するかは、SIGPIPEへの応答に依存すると結論付けるのに十分な情報が得られます-強制終了はデフォルトです。
セージ

「*プログラム* /シェル全体」を意味していましたが、明らかにunix.stackexchange.comは、最初のコメントを編集するよりも、これを2番目のコメントとして記録することを好むようです(これはスタック交換、サイト固有のポリシー決定です)。また、私は今@Rusteが...私は答えにまっすぐに行ったので、最初は私を助けなかった、一番上にこの効果にコメントしていることを確認
セージ

2

エンターテインメントのために、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

1

grepは、フラグとともに使用された場合にも返される-mため、

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コマンドではなく実行中のシェルに属しているため、コマンド出力を台無しにしないため、パイプまたはリダイレクトは行のみを出力します検索で一致。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.