
Ich möchte nach Dateien greppen, die Muster A enthalten (ich will), aber Dateien ausschließen, die Muster B enthalten (ich will nicht).
Beispiel:
read -p "...what are you looking for: " iwant
read -p "...what should not be included: " idontwant
iwant="blue car"
idontwant="red car"
Nehmen wir einfach an, ich habe die folgenden Dateien:
-rw-rw-r--. 1 terpentin terpentin 45 Jun 8 16:04 blue.car
-rw-rw-r--. 1 terpentin terpentin 44 Jun 8 16:05 mixed.car
-rw-rw-r--. 1 terpentin terpentin 40 Jun 8 16:04 red.car
find . -type f -print -exec cat {} \;
./mixed.car
blue car
red car
blue car
./red.car
red car
red car
red car
./blue.car
blue car
blue car
blue car
Wie ist es möglich, als Ergebnis nur die Datei „./blue.car“ zu erhalten?
Der Originalinhalt umfasst Hunderte langer Textdateien, weshalb es wichtig ist, so ressourcenschonend wie möglich zu sein.
Antwort1
Verwenden
find . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' -print
oder
find . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' -print
- Die Begriffe (manchmal auch „Prädikate“ genannt) in einem
find
Befehl werden charakterisiert alsTests(zB-type f
) undAktionen(z. B.-print
und-delete
). Aus der Manpage kann man schwer erkennen, dass-exec
es sich sowohl um ein Aktionund ein prüfen. So, genau wiesuchen . -Typ f -mtime -30 -name '*.txt' -lesbar -size +5Prüfung 6 Prüfung 7 Prüfung 8…
schränkt die Suche sukzessive auf Dateien ein, die alle Kriterien erfüllen (alle angegebenen Tests bestehen), sofinden . -execBefehl 1{} ';' -execBefehl 2{} ';' -execBefehl 3{} ';' …
findet Dateien, für die alle Befehle erfolgreich sind. - Jeder
find
Test kann negiert (invertiert) werden, indem man ihm ein voranstellt!
. Sofind . ! -type d
werden einfache Dateien, symbolische Links, benannte Pipes, Sockets und Gerätedateien gefunden – alles außer Verzeichnissen. - Beachten Sie, dass dies
! -exec grep …
nicht gleichbedeutend ist mit-exec grep -v …
.-exec grep -v …
findet Dateien, die mindestens eine Zeile enthalten, die nicht übereinstimmt.! -exec grep …
findet Dateien, bei denenNEINZeilen stimmen überein. - Die
-q
Option zugrep
ist offiziell ein Synonym für--quiet
, bedeutet aber auchschnell. Es wird keine Ausgabe ausgegeben (außer eventuellen Fehlermeldungen), aber es wird beendet, sobald es eine Übereinstimmung findet – es liest nicht jede Datei bis zum Ende, um zu findenjedenÜbereinstimmung. (Wenn eine Datei keine Übereinstimmungen enthält, muss sie natürlichgrep
vollständig gelesen werden, um dies festzustellen.) - Also (Kurz zusammengefasst) finden die Befehle die Dateien, für die
grep -q "$ichwill" Datei
gelingt undgrep -q "$willnicht"Datei
schlägt fehl (weil wir es mit vorangestellt haben!
). - Die beiden Befehle sind funktional gleichwertig, können aber eine unterschiedliche Leistung aufweisen (d. h. die Ausführung kann unterschiedlich lange dauern). Wenn nur wenige Dateien die Suchzeichenfolgen enthalten,
finden . -type f -exec grep -q "$iwant" {} ';' ! -exec grep -q "$idontwant" {} ';' –print
ist schneller, da dadurchgrep "$iwant"
die meisten Dateien eliminiert werden. Wenn viele der Dateien beide Zeichenfolgen enthalten, dannfinden . -type f ! -exec grep -q "$idontwant" {} ';' -exec grep -q "$iwant" {} ';' –print
wird schneller sein, weil dadurch! grep "$idontwant"
die meisten Dateien gelöscht werden.
Antwort2
Mit GNU grep
können wir die Dateinamenextraktion mit einer umsichtigen Auswahl von Regex- und Grep-Optionen durchführen:
$ grep -lzPsr '(?s:(?=.*blue)(?!.*red))' .
Wir betreiben grep im Slurp-Modus (-z), wobei die gesamte Datei als eine große Zeile behandelt wird.
Mit -l werden die Dateinamen der Dateien aufgelistet, die dem regulären Ausdruck entsprechen.
Die Option -r wird rekursiv auf allen Dateien im aktuellen Verzeichnis und darunter ausgeführt.
Mit -s wird grep stummgeschaltet, sodass keine Warnungen ausgegeben werden.
Der reguläre Ausdruck sucht in einer Datei nach dem Vorhandensein von Blau und dem Fehlen von Rot, um eine Antwort „Ja“ zu geben.
Mit -P wird die Perl-Regex-Engine in grep aufgerufen, sodass wir die Vorteile von pcre-Regexen nutzen können.