Wie kann ich einige Dateien ausschließen, die bestimmten Erweiterungen nicht mit grep entsprechen?

8

Ich möchte alle Zeilen, die das Wort enthalten, OKrekursiv aus einem Verzeichnis ausgeben . Es gibt jedoch einige Erweiterungen, die ich vom Ergebnis ausschließen muss:

*~
*.map
*.js except *.debug.js

Ich habe es versucht:

grep -r --exclude={*~,*.map} "OK" /some/dir

Abgesehen davon, dass ich nicht weiß, wie ich all diese Nicht-Debug- .jsDateien aus dem Ergebnis entfernen kann .

Fragenüberlauf
quelle

Antworten:

7

Ich würde das nur eine Sekunde durchgehen grep, um sie zu entfernen:

grep -r --exclude={\*~,\*.map} "OK" bar/ | grep -vP '(?<!debug)\.js'

Das -vkehrt die Übereinstimmung um, druckt Linien, die nicht mit dem Muster übereinstimmen, und aktiviert-P Perl-kompatible reguläre Ausdrücke, mit denen wir negative Lookbehinds verwenden können . Diese besondere regex wird übereinstimmen , .jsdas ist nicht von prececeded debugwelche Mittel (da wir die Spiele sind invertiert) , die nur die .jsDateien gedruckt werden.

Wie @QuestionOverflow in den Kommentaren hervorhob, könnte dies jedoch den unbeabsichtigten Nebeneffekt haben, Zeilen herauszufiltern , die enthalten OKund jsda das grep -vauf die gesamte Ausgabe angewendet wird, nicht nur den Dateinamen. Um dies zu vermeiden, fügen Sie einfach einen Doppelpunkt hinzu (dies wird grepverwendet, um Dateinamen vom Dateiinhalt zu trennen):

grep -r --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js:'

Dies schlägt immer noch fehl, wenn Ihre Eingabezeile enthält foo.js:oder wenn Ihr Dateiname enthält :. Verwenden Sie also natürlich einen anderen Ansatz:

grep -Tr --exclude={*~,*.map} "OK" bar/ | grep -vP '(?<!debug).js\t'

Die -TUrsachen grepfür das Drucken einer Registerkarte zwischen dem Dateinamen und dem Dateiinhalt. Wenn wir also einfach ein \tam Ende der Regex hinzufügen , stimmt es nur mit den Dateinamen überein und nicht mit dem Inhalt der Zeile.

Trotzdem ist die Verwendungfind möglicherweise sinnvoller.

terdon
quelle
1
Würde ich versehentlich Zeilen in den gewünschten Dateien ausschließen, die jedoch beide OKund .jsdieselbe Zeile enthalten?
Frage Überlauf
@QuestionOverflow ah, ja in der Tat, guter Fang. Siehe aktualisierte Antwort.
Terdon
Fantastische Antwort. Ich muss deine akzeptieren, da ich speziell nach grep frage. Vielen Dank.
Frage Überlauf
@QuestionOverflow Gern geschehen. Im Allgemeinen findist es wahrscheinlich besser für solche Dinge. Das Richtige zu grepfinden kann schwierig sein, wie Sie betont haben :).
Terdon
Ihre Lösungen schlagen fehl, wenn die failglobOption in der Shell festgelegt ist: bash: no match: --exclude=*~Sie müssen Ihre GLOB-Musterargumente zitieren --exclude, um sie vor der Shell-Erweiterung zu verbergen, z. B.--exclude={\*~,\*.map}
Ian D. Allen,
7

Ich würde verwenden find, um die Dateien zu finden und das Ergebnis durchzuleiten xargs:

$ find . -type f \! -name "*~" \
                 \! -name "*.map" \
                 \! \( -name "*.js" -and \! -name "*.debug.js" \) \
         -print0 | xargs -0 grep "OK"

Dies sucht nach jeder Datei, die nicht mit " *~", " *.map" oder " *.jsaber nicht *.debug.js" übereinstimmt .

Mit können findSie leicht nach recht komplexen Regeln suchen, und dieser Ansatz erspart Ihnen das versehentliche Entfernen von Fehlalarmen, wie dies bei double der Fall sein könnte grep.

Andreas Wiese
quelle
Schöne Antwort auch :)
Frage Überlauf
3
Ja, das ist wahrscheinlich der beste Weg, +1. Sie können auch ein zusätzliches Programm -exec grep OK {} +anstelle von verwenden xargsund vermeiden.
Terdon
2
@IDAllen nein, beachte, dass ich -exec +nicht vorgeschlagen habe -exec \;, dass so wenig Befehle wie möglich ausgeführt werden, ähnlich wie xargs.
Terdon
4

Mit können zshSie tun:

setopt extendedglob
grep OK some/dir/**/^(*~|*.map|(^*debug).js)

Vorausgesetzt natürlich, die Argumentliste ist nicht zu lang. In diesem Fall können Sie immer Folgendes tun:

printf '%s\0' some/dir/**/^(*~|*.map|(^*debug).js) | xargs -0 grep OK
Graeme
quelle
Sie könnten auch den letzten machenzshautoload zargszargs some/dir/**/^(*~|*.map|(^*debug).js) -- grep OK
nur
2

Wenn es Ihnen nichts ausmacht, die Ausgabe leicht in der falschen Reihenfolge zu sehen (wenn Sie dies tun, können Sie sie sortieren):

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir **/*.debug.js

Dies setzt **voraus , dass Ihre Shell rekursives Globbing unterstützt: zsh ist sofort einsatzbereit, bash nach dem Ausführen shopt -s globstar, ksh93 nach dem Ausführen set -o globstar.

Ohne **Unterstützung in der Shell können Sie zwei grep-Befehle verwenden:

grep -r --exclude={*~,*.map,*.js} "OK" /some/dir
grep -r --include=*.debug.js "OK" /some/dir
Gilles 'SO - hör auf böse zu sein'
quelle
Meine Shell unterstützt **, aber mit dem zusätzlichen Argument scheint etwas nicht zu stimmen **/*.debug.js, was dazu führt, dass grep OKals Verzeichnis interpretiert wird . Haben Sie versucht, es auszuführen?
Frage Überlauf
@QuestionOverflow Mein Fehler, ich hatte die Reihenfolge der Argumente vertauscht.
Gilles 'SO - hör auf böse zu sein'
1

Sie können verwenden ripgrep. Standardmäßig werden versteckte Dateien ignoriert und Ihre .gitignoreDatei respektiert .

Sie können die Einschluss- oder Ausschlussregeln mithilfe der folgenden Parameter angeben:

-g/ --glob GLOBEinschließen oder Ausschließen von Dateien und Verzeichnissen für die Suche, die dem angegebenen Glob entsprechen.

-t/ --type TYPENur Dateien suchen, die TYPE entsprechen. Es können mehrere Typflags bereitgestellt werden.

-T/ --type-not TYPESuchen Sie nicht nach Dateien, die dem Typ entsprechen.

Verwenden Sie das --type-listFlag, um alle verfügbaren Typen aufzulisten.

Hier einige einfache Beispiele:

rg -Tjs "OK"                              # Excludes *.js, *.jsx, *.vue files.
rg -tpy "OK"                              # Includes Python files.
rg --type-add 'map:*.map' -tmap PATTERN   # Excludes *.map files.
rg -g '!*.js' -g '*.debug.js' PATTERN     # Excludes *.js apart of *.debug.js.

Dies ist die komplette Lösung auszuschließen *.~, *.map, *.js, aber nicht *.debug.js:

rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' "OK"

Testen:

$ touch file.~ file.map file.js file.debug.js file.txt file.md
$ rg --files
file.debug.js
file.js
file.map
file.md
file.txt
$ rg -g '*.*' -g '!*.~' -g '!*.map' -g '!*.js' -g '*.debug.js' --files
file.debug.js
file.md
file.txt
Kenorb
quelle