
私はこのコマンドを使用して、ここで提案されているものと同様のパターンをzipファイルで見つけています。 https://superuser.com/questions/144926/unix-grep-for-a-string-within-all-gzip-files-in-all-subdirectories
find . -regex ".*/.*zip" | xargs zgrep -m 1 -E "PATTERN"
最初の一致後も Grepp は続行されます。おそらくfind
/xargs
が原因です。grep
最初の一致が見つかった後、検索を停止するにはどうすればよいでしょうか?
追伸最初の一致後に find コマンドを停止するにはどうすればよいですか?find
find の最初の一致だけでなく、grep に成功する一致の後に停止する必要があるため、機能しません。
答え1
いくつかのこと:
zgrep
圧縮されたアーカイブ内のファイルではなく、圧縮されたファイルを調べることです.z
。.gz
zip
には、アーカイブを調べるための(壊れた)
zipgrep
スクリプトがバンドルされていることがあります。ただし、このスクリプトは、アーカイブの各メンバーに対して実行されます(つまり、 eachでは、各ファイルの最初の一致が報告されます)。unzip
zip
egrep
-m1
egrep
zgrep
同様に、 には、各ファイルに対して の出力を に送るスクリプトが付属しています。はgzip
ファイルを解凍できますが、アーカイブの最初のメンバーに対してのみ、かつそれが圧縮されている場合にのみ解凍します (ファイルでは、すべてのメンバーが必ずしも圧縮されているわけではなく、特に小さいメンバーはそうではありません)。gzip -cdfq
grep
gzip -d
zip
zip
xargs
必要なコマンドを最小限に実行しますが、ファイルのリストが大きい場合は複数のコマンドが実行されることもあります。
ここでは、おそらくzipgrep
手作業で実装するのが最善策でしょう (ここでは GNU ツールを使用)。
find . -name '*.zip' -type f -exec sh -c '
unzip -Z1 "$1" |
while IFS= read -r file; do
unzip -p "$1" "$file" | grep --label="$1//$file" -Hm1 -- "$0" && exit
done' PATTERN {} \; -quit
これはファイルごとに 1 つのシェルを実行しますが、さらに多くのコマンドも実行しますzipgrep
。zipgrep
アーカイブ メンバーの名前にワイルドカード文字 ( *
、、) や ASCII 文字 0x1 から 0x1f などのさまざまな文字が含まれている場合は失敗する可能性がありますが、これは主に のバグや制限によるもので[
、を使用する場合ほど悪くはありません。?
unzip
zipgrep
答え2
試す:
find . -iname '*.zip' -print0 | xargs -0r zgrep -l -E 'PATTERN'
私は-iname
ではなくを使用しました-regex
。これはこの場合も同様に機能し、find
の奇妙な正規表現の処理よりも混乱が少ないと、私 は考えています。-print0
および はxargs -0
、スペースやシェルのメタ文字を含むファイル名が正しく処理されるために使用されます。
grep
の-l
オプションについては、man ページに記載されています。
-l, --files-with-matches
Suppress normal output; instead print the name of each input
file from which output would normally have been printed. The
scanning will stop on the first match.
最初に述べた一致はファイルごとに行われるため、複数のファイルが一致する場合は、それらすべてが印刷されます。つまり、grep は 1 つの一致を見つけた後でも、他のファイルの検索を続行することに注意してください。
最初の一致の後で停止したい場合は、grep
の--line-buffered
オプションを使用して、grep の出力を にパイプすることができますhead -1
。最初の一致が印刷されると、head
はそれを印刷して終了し、grep
には標準出力がなくなるため終了し、 がfind
続きます。
find . -iname '*.zip' -print0 | xargs -0r zgrep --line-buffered -l -E 'PATTERN' | head -1
答え3
grep
's(またはzgrep
's)-m
オプションを使用すると、読み取りが停止します。現行ファイル最初の試合では:
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines.
それは、次ファイル。例:
$ echo "hello" > foo
$ echo "hello" > bar
$ grep -m 1 hello foo bar
foo:hello
bar:hello
つまり、問題はxargs
複数のファイルをgrepしているという事実ではなく、最初に一致した後にgrep
(または)を停止させるにはzgrep
ファイル、@Stephane が提案したように小さなループを実行する必要があります。または、bash で次のようにします。
shopt -s globstar
for i in **/*.zip; do
zgrep -l pattern "$i" && break;
done
または、zipアーカイブの場合は複数のファイルを含む(@Stephane に感謝):
shopt -s globstar
for i in **/*.zip; do
if unzip -p "$i" | grep -q hello; then
echo "$i" && break;
fi;
done
答え4
grep -m 1
各ファイルの最初の一致をリストします。
最初の一致だけをリストする簡単な方法があります。パイプで処理しますhead -n 1
。検索はすぐに終了し、SIGPIPE の。
find . -regex ".*/.*zip" -print0 | xargs -0 zgrep -E "PATTERN" | head -n 1