Unix 'grep' für eine Zeichenfolge in allen gzip-Dateien in allen Unterverzeichnissen

8

Wie greife ich rekursiv nach einer Zeichenfolge in allen .gzDateien in allen Verzeichnissen und Unterverzeichnissen?

Peter Mortensen
quelle

Antworten:

13

@ Steve Weet ist fast da. Die Verwendung von / dev / null als zusätzliches Argument ist eine gute Möglichkeit, die Anzeige des Dateinamens zu erzwingen (ich werde mich daran erinnern, danke Steve), aber es wird immer noch die Ausführung für jede gefundene Datei ausgeführt - ein enormer Overhead.

Sie möchten zgrep so oft wie möglich ausführen, um jede Ausführung optimal zu nutzen:

find . -iname '*.gz' -print0 | xargs -0 zgrep PATTERN

xargsliefert zgrep so viele Argumente (Dateinamen) wie möglich und führt sie wiederholt aus, bis alle vom findBefehl bereitgestellten Dateien verwendet wurden . Mit den Optionen -print0und -0kann es funktionieren, wenn in einem der Datei- oder Verzeichnisnamen Leerzeichen vorhanden sind.

Unter Mac OS X können Sie den gleichen Effekt ohne xargs erzielen:

find . -iname '*.gz' -exec zgrep PATTERN {} +
Stephen P.
quelle
+1 Das ist wirklich schön. Ich hatte nicht bemerkt, dass Xargs mehr als ein Argument bestanden hatte. Ein Großteil meiner * nix-Befehlszeilen-Fu ist 20 Jahre alt und ich glaube nicht, dass xargs das vor 20 Jahren getan hat.
Steve Weet
Es stellt sich heraus, dass sich find auf os / x genauso verhält wie xargs
Steve Weet
1
Siehe meinen Kommentar zu Steve Weets Antwort bezüglich des '+' Endes von -exec.
Daniel Andersson
Verwenden Sie -Hdiese Option, um den Dateinamen immer mit der übereinstimmenden Zeile anzuzeigen, zumindest in GNU grep.
Daniel Andersson
1
$ zgrep --help
Usage: /bin/zgrep [OPTION]... [-e] PATTERN [FILE]...
Look for instances of PATTERN in the input FILEs, using their
uncompressed contents if they are compressed.

Also so etwas wie

find . -iname "*.gz" -exec zgrep PATTERN {} \
aioobe
quelle
Die -exec erzeugt für jede Datei, über die sie iteriert, eine neue Instanz von zgrep, um zu verhindern, dass Sie den Dateinamen sehen. Es wäre besser, zgrep -rdurch einen Baum zu gehen, oder wenn das -r nicht funktioniert, xargs zgrep
leiten Sie
Ich steige /bin/zgrep: -r: option not supportedauf mein neu installiertes Ubuntu-System.
Aioobe
Sie können xargsstattdessen stattdessen verwenden.
Noufal Ibrahim
Siehe meinen Kommentar zu Steve Weets Antwort bezüglich des '+' Endes von -exec.
Daniel Andersson
1

@aioobe ist fast da. Der Befehl erledigt die Aufgabe, teilt Ihnen jedoch nicht den Dateinamen mit

Folgendes sollte Ihnen auch den Dateinamen mitteilen:

find . -iname "*.gz" -exec zgrep PATTERN {} /dev/null \;

Durch Hinzufügen von /dev/nullwird sichergestellt, dass zgrep zwei Dateinamen sieht, sodass der Name der Datei angezeigt wird, wenn die Zeichenfolge gefunden wird

BEARBEITEN

Weitere Untersuchungen haben ergeben, dass für meinen Computer (OS / X) durch das -execzu findende Argument so viele Dateinamen wie möglich hinzugefügt werden (ähnlich wie beim xargsVerhalten).

Steve Weet
quelle
Das ist ziemlich cool, das wusste ich nicht über OSX -exec- ich bin ganz auf Portabilität bedacht, also würde ich es nicht in einem Skript verwenden, aber großartig für die Eingabeaufforderung.
Verwenden Sie für andere Versionen von find '+' anstelle von '\;' Das Beenden der exec-Anweisung erfolgt standardmäßig wie bei OSX. Die Storys in diesem Thread tun dies standardmäßig. Siehe den manuellen Eintrag für den Befehl '-exec {} +'. Es gilt nicht für alle Versionen von find, aber für die meisten modernen (z. B. in Debian-basierten Distributionen).
Daniel Andersson
Verwenden Sie -Hdiese Option, um den Dateinamen immer mit der übereinstimmenden Zeile anzuzeigen, zumindest in GNU grep anstelle des /dev/nullHacks.
Daniel Andersson
0

Das Folgende ist ein Genuss in zsh

for archive in **/*.gz; do
    echo "[${archive}] "
    gzip -dc ${archive} | grep -n "String"
done

Es kann auch arbeiten bash, kshusw ...

Johnsyweb
quelle