Ich suche nach einer Möglichkeit, Dateien zu durchsuchen, in denen zwei Wortinstanzen in derselben Datei vorhanden sind. Ich habe bis zu diesem Punkt Folgendes verwendet, um meine Suche durchzuführen:
find . -exec grep -l "FIND ME" {} \;
Das Problem, auf das ich stoße, ist, dass das Suchergebnis die Datei nicht liefert, wenn es nicht genau ein Leerzeichen zwischen "FIND" und "ME" gibt. Wie passe ich die frühere Suchzeichenfolge an, bei der beide Wörter "FIND" und "ME" in einer Datei vorhanden sind und nicht "FIND ME"?
Ich benutze AIX.
grep -E
/egrep
, der alle Muster beschreibt, an denen Sie interessiert sind (und+
anstelle dessen,;
wenn Ihre Suche Unterstützung bietet)+
.Antworten:
Mit GNU-Tools:
Sie können standardmäßig Folgendes tun:
Aber das würde zwei greps pro Datei ausführen. Um zu vermeiden, dass so viele
grep
s ausgeführt werden und trotzdem portabel sind, während Zeichen in Dateinamen zulässig sind, können Sie Folgendes tun:Die Idee ist, die Ausgabe von
find
in ein Format zu konvertieren, das für xargs geeignet ist (das ein Leerzeichen (SPC / TAB / NL, und die anderen Leerzeichen von Ihrem Gebietsschema mit einigen Implementierungen vonxargs
), getrennte Liste von Wörtern, bei denen einfache, doppelte Anführungszeichen und umgekehrte Schrägstriche möglich sind Leerzeichen und einander entkommen).Im Allgemeinen können Sie die Ausgabe von
find -print
nicht nachbearbeiten, da die Dateinamen durch ein Zeilenumbruchzeichen getrennt werden und die in Dateinamen enthaltenen Zeilenumbrüche nicht ausgeblendet werden. Zum Beispiel wenn wir sehen:Wir haben keine Möglichkeit herauszufinden, ob es sich um eine Datei
b
in einem Verzeichnis handelta<NL>.
oder ob es sich um die beiden Dateien handelta
undb
.Durch die Verwendung von
.//.
, weil//
in einem Dateipfad nicht anders angezeigt werden kann als durchfind
(weil es kein Verzeichnis mit einem leeren Namen gibt und/
in einem Dateinamen nicht zulässig ist), wissen wir, dass, wenn wir eine Zeile sehen, die enthält//
, das ist die erste Zeile eines neuen Dateinamens. Wir können diesenawk
Befehl also verwenden, um alle Zeilenumbrüche außer denen, die diesen Zeilen vorangehen , zu maskieren.Wenn wir das obige Beispiel nehmen,
find
würde im ersten Fall (eine Datei) ausgegeben:Welcher awk entkommt:
Das
xargs
sieht es als ein Argument. Und im zweiten Fall (zwei Dateien):Was
awk
so belassen würde,xargs
sieht also zwei Argumente.quelle
find ... -print0
undgrep --null
stattdessen verwenden?grep --null
(aka -Z) wird im ersten verwendet, ist aber eine GNU-Erweiterung.-print0
(eine andere GNU-Erweiterung) würde hier nicht helfen..//.
bedeutet, und frage mich, wie ich das ändern kann, um ein Argument von der Kommandozeile zu akzeptieren, sagen wir$1
?-print0
mitfind
und-0
mit zu verwendenxargs
?find -print0
nirgends in meiner Antwort.Wenn die Dateien in einem einzigen Verzeichnis sind und deren Namen enthalten keine Leerzeichen, Tabulator, Newline
*
,?
noch[
Zeichen und beginnen Sie nicht mit-
noch.
wird dies eine Liste von Dateien erhalten enthält ME, dann schmal , dass bis auf diejenigen , die Enthält auch FIND.quelle
grep -l CategoryLinearAxis `grep -l labelJsFunction *`
nach Dateien gesucht, die beide Attribute enthalten. Was für ein perfekter Weg, es zu tun. +1Mit
awk
könnten Sie auch laufen:Es verwendet
cx
undcy
für die Linien zu zählen passendenFIND
und jeweilsME
.END
Wenn in dem Block beide Zähler> 0 sind, wird derFILENAME
.Dies wäre schneller / effizienter mit
gnu awk
:quelle
Oder benutze
egrep -e
odergrep -E
mag das:find . -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;
oder
find . -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +
Mit
+
dem Befehl make find (sofern unterstützt) werden mehrere Datei- (Pfad-) Namen als Argumente zum Befehl hinzugefügt, der bearbeitet wird-exec
. Dies spart Prozesse und ist viel schneller, als\;
wenn der Befehl für jede gefundene Datei einmal aufgerufen wird.-type f
Stimmt nur mit Dateien überein, um ein Greifen in einem Verzeichnis zu vermeiden.'(ME.*FIND|FIND.*ME)'
ist ein regulärer Ausdruck, der mit jeder Zeile übereinstimmt, die "ME" gefolgt von "FIND" oder "FIND" gefolgt von "ME" enthält. (einfache Anführungszeichen, um zu verhindern, dass die Shell Sonderzeichen interpretiert).Fügen Sie
-i
demgrep
Befehl ein hinzu, damit zwischen Groß- und Kleinschreibung nicht unterschieden wird.Verwenden Sie, um nur Zeilen abzugleichen, bei denen "FIND" vor "ME" steht
'FIND.*ME'
.Leerzeichen (1 oder mehr, aber nichts anderes) zwischen den Wörtern benötigen:
'FIND +ME'
So lassen Sie Leerzeichen (0 oder mehr, aber nichts anderes) zwischen den Wörtern zu:
'FIND *ME'
Die Kombinationen mit regulären Ausdrücken sind endlos. Wenn Sie nur nacheinander abgleichen möchten, ist egrep sehr leistungsfähig.
quelle
find
in der Frage.Wenn man die akzeptierte Antwort betrachtet, scheint sie komplexer zu sein, als es sein muss. GNU-Versionen von
find
undgrep
undxargs
unterstützen NULL-terminierte Strings. Es ist so einfach wie:Sie können Ihren
find
Befehl so ändern , dass er nach den gewünschten Dateien filtert. Er funktioniert mit Dateinamen, die beliebige Zeichen enthalten. ohne die zusätzliche Komplexität dessed
Parsens. Wenn Sie die Dateien weiterverarbeiten möchten, fügen Sie eine weitere--null
zur letzten hinzugrep
Und als Funktion:
Verwenden Sie natürlich die akzeptierte Antwort, wenn Sie keine GNU-Versionen dieser Tools ausführen.
quelle
--null
,--print0
,-0
Sind alle Erweiterungen GNU. Obwohl einige von ihnen heutzutage in anderen Implementierungen zu finden sind, sind sie immer noch nicht portierbar und nicht im POSIX- oder Unix-Standard.