
Ich verwende diesen Befehl, um Muster in Zip-Dateien zu finden (ähnlich dem hier vorgeschlagenen) https://superuser.com/questions/144926/unix-grep-für-eine-zeichenfolge-innerhalb-aller-gzip-dateien-in-allen-unterverzeichnissen
find . -regex ".*/.*zip" | xargs zgrep -m 1 -E "PATTERN"
Das Grepping wird nach dem ersten Treffer fortgesetzt. Wahrscheinlich ist find
/ xargs
der Übeltäter. Wie kann ich die Suche nach grep
dem ersten Treffer beenden?
PSWie stoppe ich den Suchbefehl nach dem ersten Treffer?funktioniert nicht, da find
nach einer Übereinstimmung gestoppt werden muss, die auf grep erfolgreich ist, und nicht nur nach der ersten Übereinstimmung von find.
Antwort1
Verschiedene Dinge:
zgrep
dient zum Durchsuchen.z
komprimierter.gz
Dateien, nicht von Dateien in komprimiertenzip
Archiven.Manchmal ist ein (defektes)
zipgrep
Skript im Lieferumfang enthaltenunzip
, um in Archiven zu suchen . Es wird jedoch auf jedem Mitglied des Archivszip
ausgeführt (sodass „with each“ die erste Übereinstimmung für jede Datei melden würde).egrep
-m1
egrep
zgrep
, ähnlich ist ein mitgeliefertes Skript,gzip
das die Ausgabe von für jede Datei einspeistgzip -cdfq
.grep
kann Dateiengzip -d
dekomprimierenzip
, tut dies aber nur für das erste Mitglied des Archivs und nur, wenn es komprimiert ist (inzip
Dateien sind nicht unbedingt alle Mitglieder komprimiert, insbesondere kleine).xargs
führt so wenige Befehle wie nötig aus, kann aber trotzdem mehrere ausführen, wenn die Dateiliste groß ist.
zipgrep
Hier ist die Implementierung per Hand (hier mit GNU-Tools) wahrscheinlich die beste Lösung :
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
Dadurch wird eine Shell pro Datei ausgeführt, aber das wäre zipgrep
auch zipgrep
bei vielen weiteren Befehlen der Fall.
Es kann fehlschlagen, wenn die Namen der Archivmitglieder Platzhalterzeichen ( *
, [
, ?
) oder andere Zeichen wie die ASCII-Zeichen 0x1 bis 0x1f und verschiedene andere enthalten. Dies liegt jedoch hauptsächlich an Fehlern und Einschränkungen in unzip
und ist nicht so schlimm wie bei der Verwendung von zipgrep
.
Antwort2
Versuchen:
find . -iname '*.zip' -print0 | xargs -0r zgrep -l -E 'PATTERN'
Ich habe -iname
anstelle von verwendet -regex
– es funktioniert hierfür genauso gut und ist meiner Meinung nach weniger verwirrend als find
die seltsame Regex-Verarbeitung von . -print0
und xargs -0
werden verwendet, damit alle Dateinamen mit Leerzeichen oder Shell-Metazeichen korrekt verarbeitet werden.
grep
Die -l
Option ist in der Manpage dokumentiert:
-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.
Die erste angegebene Übereinstimmung gilt pro Datei. Wenn also mehrere Dateien übereinstimmen, werden sie alle gedruckt. Beachten Sie, dass dies bedeutet, dass grep mit der Suche in den anderen Dateien fortfährt, auch nachdem es eine Übereinstimmung gefunden hat.
Wenn Sie möchten, dass es nach der allerersten Übereinstimmung stoppt, können Sie die Option grep
von verwenden --line-buffered
und die Ausgabe von grep in umleiten head -1
. Wenn die erste Übereinstimmung gedruckt wird, head
wird sie gedruckt und beendet, grep
hat keine Standardausgabe mehr, wird also beendet und find
folgt.
find . -iname '*.zip' -print0 | xargs -0r zgrep --line-buffered -l -E 'PATTERN' | head -1
Antwort3
grep
Die Option 's (oder zgrep
's) -m
führt dazu, dass das Lesen deraktuelle Dateizum ersten Spiel:
-m NUM, --max-count=NUM
Stop reading a file after NUM matching lines.
Das wird sie nicht davon abhalten, dienächsteDatei. Beispiel:
$ echo "hello" > foo
$ echo "hello" > bar
$ grep -m 1 hello foo bar
foo:hello
bar:hello
Das Problem ist also nicht xargs
, dass Sie mehrere Dateien greppen. Um nach der ersten Übereinstimmung anzuhalten grep
(oder anzuhalten),zgrep
Datei, müssten Sie eine kleine Schleife ausführen, wie @Stephane vorgeschlagen hat. Oder so etwas wie das hier mit bash :
shopt -s globstar
for i in **/*.zip; do
zgrep -l pattern "$i" && break;
done
Oder für Zip-Archive, diemehrere Dateien enthalten(danke @Stephane):
shopt -s globstar
for i in **/*.zip; do
if unzip -p "$i" | grep -q hello; then
echo "$i" && break;
fi;
done
Antwort4
grep -m 1
listet die erste Übereinstimmung jeder Datei auf.
Es gibt eine einfache Möglichkeit, nur die erste Übereinstimmung aufzulisten: pipe through head -n 1
. Die Suche wird bald an einemSIGPIPE.
find . -regex ".*/.*zip" -print0 | xargs -0 zgrep -E "PATTERN" | head -n 1