Wie finde ich Dateien, die kein bestimmtes Zeichenfolgenmuster enthalten?

536

Wie finde ich die Dateien im aktuellen Verzeichnis heraus, die das Wort nicht enthalten foo(using grep)?

Senthil Kumar
quelle

Antworten:

818

Wenn Ihr grep die Option -L(oder --files-without-match) hat:

$ grep -L "foo" *
Ghostdog74
quelle
1
Wie bereits an anderer Stelle erwähnt, hilft ack standardmäßig dabei, .svn-Dateien (Subversion) zu vermeiden.
GuruM
11
@ GuruM Dies kann in GNU grep durch Exportieren der Variablen erfolgen GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git': ^)
bufh
6
Oder das Äquivalent mit ag :ag -L 'foo'
Bischof
5
Funktioniert wie Magie! Hinweis: Verwenden Sie -rLanstelle von -L, um Unterverzeichnisse
abzugleichen
1
@Larry - Eine sauberere Möglichkeit, Globbing-Probleme zu vermeiden, besteht darin, die lange Option "leer" wie folgt zu verwenden: grep -L 'foo' -- *Standardmäßig werden Befehle mit langen Optionen verwendet, --um anzuzeigen, dass nach diesem Punkt keine Optionen mehr vorhanden sind.
Paddy Landau
45

Schau es dir an ack. Es schließt den .svnAusschluss automatisch für Sie aus, gibt Ihnen reguläre Perl-Ausdrücke und ist ein einfacher Download eines einzelnen Perl-Programms.

Das Äquivalent zu dem, was Sie suchen, sollte sein in ack:

ack -L foo
Andy Lester
quelle
23

Sie können es mit grep alleine machen (ohne zu finden).

grep -riL "foo" .

Dies ist die Erklärung der verwendeten Parameter grep

     -L, --files-without-match
             each file processed.
     -R, -r, --recursive
             Recursively search subdirectories listed.

     -i, --ignore-case
             Perform case insensitive matching.

Wenn Sie l(Kleinbuchstaben) verwenden, erhalten Sie das Gegenteil (Dateien mit Übereinstimmungen)

     -l, --files-with-matches
             Only the names of files containing selected lines are written
Adrian
quelle
17

Der folgende Befehl gibt mir alle Dateien, die das Muster nicht enthalten foo:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0
Senthil Kumar
quelle
4
Sie möchten die grep 0 am Ende in grep 0 $ ändern (andernfalls erhalten Sie fehlerhafte Übereinstimmungen mit Dateien, deren Dateiname das Zeichen 0 enthält).
Clouseau
9
@clouseau ist meistens richtig ... grep '0$'Würde aber auch Dateien mit Vielfachen von 10 Zeilen abgleichen ! Sie müssen grep ':0$'am Ende nach einem expliziten ': 0' am Ende der Zeile suchen. Dann erhalten Sie nur Dateien mit übereinstimmenden Nullzeilen.
TrinitronX
Das UNIX, auf dem ich mich befinde, hatte keine Versionen von find oder grep mit diesen Optionen, daher musste ich den in anderen Kommentaren vorgeschlagenen Befehl "ack" verwenden.
KC Baltz
14

Der folgende Befehl schließt die Notwendigkeit aus, dass die Suche die svnOrdner mithilfe einer Sekunde herausfiltert grep.

grep -rL "foo" ./* | grep -v "\.svn"
user999305
quelle
9

Sie benötigen tatsächlich:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$
Forrest Tiffany
quelle
6

Ich hatte viel Glück mit

grep -H -E -o -c "foo" */*/*.ext | grep ext:0

Meine Versuche mit grep -vgaben mir nur alle Zeilen ohne "foo".

Johnny
quelle
4

Problem

Ich muss ein großes Projekt umgestalten, das .phtmlDateien verwendet, um HTML mit Inline-PHP-Code zu schreiben. Ich möchte stattdessen Moustache- Vorlagen verwenden. Ich möchte alle .phtmlGiles finden, die die Zeichenfolge nicht enthalten, new Mustacheda diese noch neu geschrieben werden müssen.

Lösung

find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

Erläuterung

Vor den Rohren:

Finden

find . Suchen Sie rekursiv nach Dateien, beginnend in diesem Verzeichnis

-iname '*.phtml'Der Dateiname muss enthalten .phtml(das imacht es unabhängig von Groß- und Kleinschreibung)

-exec 'grep -H -E -o -c 'new Mustache' {}'Führen Sie den grepBefehl auf jedem der übereinstimmenden Pfade aus

Grep

-H Drucken Sie Dateinamen-Header immer mit Ausgabezeilen.

-E Interpretieren Sie das Muster als erweiterten regulären Ausdruck (dh zwingen Sie grep, sich als egrep zu verhalten).

-o Druckt nur den passenden Teil der Zeilen.

-c Es wird nur eine Anzahl ausgewählter Zeilen in die Standardausgabe geschrieben.


Dies gibt mir eine Liste aller Dateipfade .phtml, die mit enden , mit einer Zählung, wie oft die Zeichenfolge new Mustachein jedem von ihnen vorkommt.

$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Die erste Pipe grep :0$filtert diese Liste so, dass sie nur Zeilen enthält, die auf Folgendes enden :0:

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

Die zweite Pipe sed 's/..$//'entfernt die letzten beiden Zeichen jeder Zeile und lässt nur die Dateipfade übrig.

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml
Gruffy
quelle
3

Wenn Sie git verwenden, werden alle nachverfolgten Dateien durchsucht:

git grep -L "foo"

und Sie können in einer Teilmenge der verfolgten Dateien suchen, wenn Sie das shopt -s globstarGlobbing des Unterverzeichnisses ** aktiviert haben ( in .bashrc, siehe dies ):

git grep -L "foo" -- **/*.cpp
Zak
quelle
1

Mein grep hat keine -L Option. Ich finde eine Problemumgehung, um dies zu erreichen.

Die Ideen sind:

  1. um den gesamten Dateinamen, der die verdiente Zeichenfolge enthält, in eine txt1.txt zu speichern.
  2. Speichern Sie den gesamten Dateinamen im Verzeichnis in einer txt2.txt.
  3. Machen Sie den Unterschied zwischen der 2-Dump-Datei mit dem Befehl diff.

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    
user6305682
quelle
Ich vergesse die Befehle, aber anstatt Dateinamen diffauszugeben , können Sie tatsächlich einen zwischen zwei Ausgabestreams ausführen (ich denke, Sie umgeben die Befehle mit Klammern, und irgendwo gibt es auch eine spitze Klammer), wenn Ihr System dies unterstützt, was ich denke ist die Frage, da es nicht unterstütztgrep -L
Dexygen
1

find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

Sie können den Filter unter "find" und die Ausschlusszeichenfolge unter "grep -vwE" angeben. Verwenden Sie mtime unter find, wenn Sie auch nach geänderter Zeit filtern müssen.

zandeep
quelle
Dies scheint mir alle Zeilen ohne die Zeichenfolge zu zeigen, das OP fragt nur nach den Dateinamen.
Ben Farmer
1

Fehlerbericht öffnen

Wie von @tukan kommentiert, gibt es für Ag einen offenen Fehlerbericht bezüglich der -L/ --files-without-matchesflag:

Da der Fehlerbericht kaum Fortschritte macht, sollte auf die -Lunten genannte Option nicht vertraut werden , solange der Fehler nicht behoben wurde. Verwenden Sie stattdessen verschiedene in diesem Thread vorgestellte Ansätze. Zitieren eines Kommentars für den Fehlerbericht [Hervorhebung von mir]:

Irgendwelche Updates dazu? -LIgnoriert Übereinstimmungen in der ersten Zeile der Datei vollständig. Wenn dies nicht bald behoben wird, sollte das Flag vollständig entfernt werden, da es effektiv überhaupt nicht wie angekündigt funktioniert .


The Silver Searcher - Ag (vorgesehene Funktion - siehe Fehlerbericht)

Als leistungsstarke Alternative zu grepkönnen Sie The Silver Searcher - Ag verwenden :

Ein Code-Suchwerkzeug ähnlich wie ack mit Schwerpunkt auf Geschwindigkeit.

Beim Betrachten man agfinden wir die Option -Loder --files-without-matches:

...

OPTIONS
    ...

    -L --files-without-matches
           Only print the names of files that don´t contain matches.

Dh, um rekursiv nach Dateien zu suchen, die nicht übereinstimmen foo, aus dem aktuellen Verzeichnis:

ag -L foo

Um nur das aktuelle Verzeichnis nach Dateien zu durchsuchen , die nicht übereinstimmen foo, geben Sie einfach --depth=0für die Rekursion Folgendes an:

ag -L foo --depth 0
dfri
quelle
Dies schlägt von Zeit zu Zeit aufgrund des -LFehlers fehl - github.com/ggreer/the_silver_searcher/issues/238
tukan
@ Tukan danke für die Aufforderung. Ich habe die Antwort aktualisiert. Wählen Sie, die Antwort nicht zu löschen, sondern mit den Informationen zum Fehler zu öffnen.
dfri
1

Eine weitere Alternative, wenn grep nicht über die Option -L verfügt (z. B. IBM AIX), sondern nur grep und die Shell:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
JMD
quelle
-4
grep -irnw "filepath" -ve "pattern"

oder

grep -ve "pattern" < file

Der obige Befehl gibt uns das Ergebnis, wenn -v die Umkehrung des gesuchten Musters findet

Jay
quelle
1
Dadurch werden die Linien gedruckt, die das Muster nicht enthalten. Sie können die -lOption hinzufügen , nur den Dateinamen zu drucken. aber das druckt immer noch die Namen der Datei , die enthält jede Zeile , die das Muster nicht enthalten. Ich glaube, das OP möchte die Dateien finden, die keine Zeile enthalten, die das Muster enthält.
Tripleee
Der von Ihnen angegebene Befehl listet Dateien in "Dateipfad" mit all ihren Zeilen auf, die kein "Muster" enthalten.
Aprodan
-6

Der folgende Befehl kann Ihnen helfen, die Zeilen zu filtern, die den Teilstring "foo" enthalten.

cat file | grep -v "foo"
Walkerlin
quelle
2
Dadurch werden nicht übereinstimmende Zeilen gedruckt, keine Namen von Dateien, die in keiner Zeile übereinstimmen. Um die Verletzung zu beleidigen, ist es eine nutzlose Verwendung voncat .
Tripleee