Kommentare
- Was meinst du? durch " den gesamten Teil jeder Zeichenfolge "? Sie möchten nicht, dass ' die gesamte Zeile gedruckt wird?
- Können Sie bestätigen, dass übereinstimmende Dateien beide " foo " und " 321 " aber nicht nur " foo " oder nur " 321 "?
- Mir gefällt, wie es ' s
321
anstelle vonbar
ist: – D
Antwort
GNU grep
Sollte etwas schneller sein, da die zweite grep
kann eine Liste von Dateien bearbeiten.
grep -lZ "foo" * | xargs -0 grep -l "321"
POSIX grep mit find
find
ist nützlicher, wenn Sie rekursive Verzeichnisse durchsuchen möchten (in diesem Fall verlieren Sie die -mindepth
und -maxdepth
Optionen.
find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} +
Kommentare
-
-r
hat beim erstengrep
einwandfrei funktioniert, um diese GNU-Lösung für mich rekursiv zu machen. anstatt die POSIX-Zeile mit all diesenexec
s
Antwort
Sie können dies mit einem kurzen Skript tun:
for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done
Sie können dies auch in einer Zeile tun:
for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done
grep
gibt 0 (true) zurück, wenn der String gefunden wurde, und die &&
, die die Befehle trennt, bedeutet dies Der zweite wird nur ausgeführt, wenn der erste wahr war. Die Option -q
stellt sicher, dass grep
nichts ausgibt.
Das Echo wird nur ausgeführt, wenn beide Zeichenfolgen vorhanden sind gefunden in der gleichen Datei.
Ich dachte über eine andere Art, es zu tun. Diese Methode ist wahrscheinlich effizienter, wenn die betreffenden Dateien größer als Ihr installierter Arbeitsspeicher sind, da sie nur einmal grep
durch jede Datei gehen müssen.
for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done
und die einzeilige Version:
for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done
Kommentare
- Für Ihre effizientere Lösung: Was ist, wenn die Datei " foo foo " enthält?
- That ' ist das, wofür
uniq | sort | uniq
ist. " foo foo " ist eine Zeile, aber " foo 321 " besteht letztendlich aus zwei Zeilen, dagrep -o
alle gefundenen Zeichenfolgen in separaten Zeilen ausgibt, auch wenn sie in derselben Zeile begonnen haben. - Wenn die Dateien so groß werden, dass es in Ordnung wäre, mindestens sechs Mal pro Datei zu gabeln, ist es wahrscheinlich sinnvoll, stattdessen awk zu verwenden, damit die Dateien nicht bis zum Ende durchsucht werden müssen.
- @Ladadadada got es. 🙂
- @HaukeLaging
grep -q
undgrep -l
suchen nicht bis zum Ende der Datei: Sie werden sofort beendet als Übereinstimmung gefunden wird. Ich frage mich, warum die erste Lösung nicht ' tfor FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done
Antwort ist
Seltsam. Für mich funktionieren beide Varianten (grep (GNU grep) 2.13):
grep "foo\|321" grep -E "foo|321"
Bearbeiten Sie 1 – Nur Dateien mit beiden Übereinstimmungen anzeigen
Die Antwort for file in *
funktioniert, kann jedoch zu einem Leistungsalptraum werden (für große Mengen von Dateien) ): mindestens zwei Prozesse pro Datei. Dies ist schneller (in der GNU-Welt):
find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2
string1 sollte derjenige sein, der zu weniger Übereinstimmungen führt.
Kommentare
- Der Fragesteller sucht nach einem Ergebnis, das nur dann true zurückgibt, wenn eine Datei beide Zeichenfolgen enthält, anstatt nur mindestens einer zu entsprechen.
- Das gefällt mir
--files-with-matches
Option. Lesen Sie es einfach in der Manpage nach und es führt dazu, dass grep stoppt, nachdem es die erste Übereinstimmung gefunden hat. Dies bedeutet, dass ' für große Dateien sehr effizient ist, wenn die Übereinstimmung früh auftritt. Es heißt auch, dass die kurze Option-l
von POSIX angegeben wird, sodass sie außerhalb der GNU-Welt verwendet werden kann. - @Ladadadada Die Effizienz ist kein Vorteil gegenüber Ihrer -q aber. Als ich GNU erwähnte, dachte ich nicht ' an –files-with-match, sondern an -0 / –null.Was mir gerade in den Sinn kommt: Die Pfadnamenerweiterung enthält eine alphabetische Sortierung (wirklich schlecht: Es scheint, dass ' nicht einmal deaktiviert werden kann), sodass für große Mengen von Dateien sogar Ihre
for file in *
macht wirklich keinen Spaß mehr. - In der Tat wären die Effizienzoptimierungen für einige große Dateien ganz anders als für viele kleine und
*
funktioniert nach einigen tausend Dateien einfach nicht mehr '. - @Ladadadada ' funktioniert nicht als Teil einer Befehlszeile für einen externen Befehl:
grep foo *
Aberfor file in *
ist eine Shell-interne Struktur, also würde ich annehmen dass das Befehlszeilenlimit hier nicht anwendbar ist.
Antwort
Grundsätzlich, um alle Dateien einschließlich einer bestimmten zu finden Zeichenfolge in einem Verzeichnis können Sie verwenden:
grep -lir "pattern" /path/to/the/dir
-
-l
: um diesen Scan durchzuführen stoppt bei der ersten Übereinstimmung -
-i
: um Groß- und Kleinschreibung sowohl im Muster als auch in den Eingabedateien zu ignorieren -
-r
: Durchsuchen Sie alle Dateien im Verzeichnis rekursiv.
Um nach zwei Mustern zu suchen, versuchen Sie Folgendes:
grep -lr "321" $(grep -lr "foo" /path/to/the/dir)
Kommentare
- Langweilige Standardkommentare zu
$()
, die Leerzeichen nicht gut behandeln, gelten. In der Praxis funktioniert dieser Befehl für einen Liner in der Shell einwandfrei.
Antwort
Sollte
grep -e "foo" -e "321" *
Verwenden Sie -e für mehrere Muster
BEARBEITEN
Falls beide übereinstimmen müssen:
grep -e ".*foo.*321.*" *
Wenn die Reihenfolge keine Rolle spielt:
grep -e ".*foo.*321.*" ".*321.*foo.*" *
Kommentare
- Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag.
- @mdpc Ich denke, er liefert eine Antwort. Was lässt Sie anders denken?
- @HaukeLaging Weil es zurückgibt, wenn eines der Muster übereinstimmt. Das OP sucht nach einem Fall, in dem es nur dann true zurückgibt, wenn beide in der Datei gefunden werden.
- Nach meinem Verständnis werden nur Dateien gefunden, in denen beide Zeichenfolgen in derselben Zeile enthalten sind (I. ' denke nicht. Entspricht standardmäßig Zeilenumbrüchen)