
我使用此命令來查找 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