我使用此命令来查找 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"
第一场比赛结束后,Greping 仍在继续。可能find
/xargs
是罪魁祸首。如何在grep
找到第一个匹配项后停止查找?
聚苯乙烯如何在第一次匹配后停止查找命令?不起作用,因为find
需要在 grep 成功的匹配之后停止,而不仅仅是 find 的第一个匹配。
答案1
几件事:
zgrep
是查看压缩文件,.z
而不是压缩档案.gz
内的文件。zip
有一个(损坏的)
zipgrep
脚本有时与unzip
, 捆绑在一起,用于查看zip
档案,但它的作用是egrep
在档案的每个成员上运行(因此-m1
每个成员egrep
都会报告每个文件的第一个匹配项)。zgrep
,类似的是一个附带的脚本,它为每个文件提供togzip
的输出。可以解压缩文件,但仅对存档的第一个成员执行此操作,并且仅当它被压缩时(在文件中,并非所有成员都必须被压缩,尤其是小成员)。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
每个文件运行一个 shell,但也会zipgrep
运行zipgrep
更多命令。
如果存档成员的名称包含通配符 ( *
, [
, ?
) 或其他字符(如 ASCII 字符 0x1 到 0x1f 以及各种其他字符),则可能会失败,但这主要是由于 中的错误和限制unzip
,而且这并不像使用 时那么糟糕zipgrep
。
答案2
尝试:
find . -iname '*.zip' -print0 | xargs -0r zgrep -l -E 'PATTERN'
我用过-iname
而不是-regex
- 它对此也很有效,并且在我看来,比find
奇怪的正则表达式处理更容易混淆。 使用-print0
和xargs -0
以便正确处理其中包含空格或 shell 元字符的任何文件名。
grep
的-l
选项记录在手册页中:
-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 将继续搜索其他文件,即使在找到一个匹配项之后也是如此。
如果您希望它在第一个匹配后停止,您可以使用grep
s--line-buffered
选项并将 grep 的输出通过管道传输到head -1
.当打印第一个匹配时,head
将打印它并终止,grep
将不再有标准输出,因此它将终止,find
并将跟随。
find . -iname '*.zip' -print0 | xargs -0r zgrep --line-buffered -l -E 'PATTERN' | head -1
答案3
grep
的(或zgrep
)-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
。搜索很快就会因信号管道。
find . -regex ".*/.*zip" -print0 | xargs -0 zgrep -E "PATTERN" | head -n 1