Ich möchte Dateien finden, die "abc" UND "efg" in dieser Reihenfolge haben, und diese beiden Zeichenfolgen befinden sich in dieser Datei in unterschiedlichen Zeilen. ZB: eine Datei mit Inhalt:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
Sollte abgestimmt sein.
Antworten:
Grep reicht für diesen Vorgang nicht aus.
pcregrep, das in den meisten modernen Linux-Systemen zu finden ist, kann als verwendet werden
wo
-M
,--multiline
erlauben Muster mehr als eine Zeile passenEs gibt auch einen neueren pcre2grep . Beide werden vom PCRE-Projekt bereitgestellt .
pcre2grep ist für Mac OS X über Mac-Ports als Teil des Ports verfügbar
pcre2
:und über Homebrew als:
oder für pcre2
pcre2grep ist auch unter Linux verfügbar (Ubuntu 18.04+)
quelle
-M, --multiline
- Ermöglicht, dass Muster mit mehr als einer Zeile übereinstimmen.'abc.*(\n|.)*?efg'
.*
->'abc(\n|.)*?efg'
um die Regex kürzer zu machen (und um pedantisch zu sein)pcregrep
macht die Sache einfacher, wird abergrep
auch funktionieren. Siehe beispielsweise stackoverflow.com/a/7167115/123695Ich bin mir nicht sicher, ob es mit grep möglich ist, aber sed macht es sehr einfach:
quelle
sed
, aber wenn ich noch nie einen solchen Ausdruck gesehen habe.Hier ist eine Lösung, die von dieser Antwort inspiriert ist :
wenn 'abc' und 'efg' in derselben Zeile stehen können:
wenn 'abc' und 'efg' in unterschiedlichen Zeilen stehen müssen:
Parameter:
-z
Behandeln Sie die Eingabe als eine Reihe von Zeilen, die jeweils durch ein Null-Byte anstelle einer neuen Zeile abgeschlossen werden. dh grep behandelt die Eingabe als eine große Zeile.-l
Druckname jeder Eingabedatei, aus der normalerweise die Ausgabe gedruckt worden wäre.(?s)
aktiviere PCRE_DOTALL, was bedeutet, dass '.' findet ein Zeichen oder eine neue Zeile.quelle
l
. AFAIK gibt es keine-1
Nummernoption.-z
Optionen grep angegeben ist, um Zeilenumbrüche so zu behandeln,zero byte characters
warum benötigen wir dann das(?s)
in der Regex? Wenn es sich bereits um ein Nicht-Zeilenumbruchzeichen handelt, sollte es dann nicht.
direkt zugeordnet werden können?sed sollte als oben angegebenes Poster LJ ausreichen,
anstelle von! d können Sie einfach p zum Drucken verwenden:
quelle
Ich habe mich stark auf pcregrep verlassen, aber mit neuerem grep müssen Sie pcregrep für viele seiner Funktionen nicht installieren. Einfach benutzen
grep -P
.Im Beispiel der OP-Frage denke ich, dass die folgenden Optionen gut funktionieren, wobei die zweitbeste zu meinem Verständnis der Frage passt:
Ich habe den Text als / tmp / test1 kopiert und das 'g' gelöscht und als / tmp / test2 gespeichert. Hier ist die Ausgabe, die zeigt, dass die erste die übereinstimmende Zeichenfolge und die zweite nur den Dateinamen anzeigt (typisch -o zeigt Übereinstimmung an und typisch -l zeigt nur Dateinamen an). Beachten Sie, dass das 'z' für mehrzeilig erforderlich ist und das '(. | \ N)' bedeutet, dass entweder 'irgendetwas anderes als Zeilenumbruch' oder 'Zeilenumbruch' übereinstimmt - dh alles:
Um festzustellen, ob Ihre Version neu genug ist, führen Sie sie aus
man grep
und prüfen Sie, ob oben etwas Ähnliches angezeigt wird:Das ist aus GNU grep 2.10.
quelle
Dies kann einfach durchgeführt werden, indem zuerst
tr
die Zeilenumbrüche durch ein anderes Zeichen ersetzt werden:Hier verwende ich das Alarmzeichen
\a
(ASCII 7) anstelle einer neuen Zeile. Dies wird in Ihrem Text fast nie gefunden undgrep
kann mit einem.
oder speziell mit einem übereinstimmen\a
.quelle
\0
und brauchtegrep -a
und passte auf\x00
... Sie haben mir geholfen, zu vereinfachen!echo $log | tr '\n' '\0' | grep -aoE "Error: .*?\x00Installing .*? has failed\!" | tr '\0' '\n'
ist jetztecho $log | tr '\n' '\a' | grep -oE "Error: .*?\aInstalling .*? has failed\!" | tr '\a' '\n'
grep -o
.awk Einzeiler:
quelle
abc
bis zum Ende der Datei gedruckt, wenn das Endmuster nicht in der Datei vorhanden ist oder das letzte Endmuster fehlt. Sie können das beheben, aber es wird das Skript ziemlich kompliziert./efg/
von der Ausgabe ausschließen?Sie können dies sehr einfach tun, wenn Sie Perl verwenden können.
Sie können dies auch mit einem einzelnen regulären Ausdruck tun. Dazu muss jedoch der gesamte Inhalt der Datei in einer einzigen Zeichenfolge zusammengefasst werden, was bei großen Dateien möglicherweise zu viel Speicherplatz beansprucht. Der Vollständigkeit halber ist hier diese Methode:
quelle
.*?
) verwenden, um eine minimale Übereinstimmung zu erzielen.Ich weiß nicht, wie ich das mit grep machen würde, aber ich würde so etwas mit awk machen:
Sie müssen jedoch vorsichtig sein, wie Sie dies tun. Möchten Sie, dass die Regex mit der Teilzeichenfolge oder dem gesamten Wort übereinstimmt? Fügen Sie gegebenenfalls \ w Tags hinzu. Auch wenn dies genau dem entspricht, wie Sie das Beispiel angegeben haben, funktioniert es nicht ganz, wenn abc ein zweites Mal nach efg erscheint. Wenn Sie damit umgehen möchten, fügen Sie im Fall / abc / usw. ein Gegebenenfalls hinzu.
quelle
Das kannst du leider nicht. Aus den
grep
Dokumenten:quelle
grep -Pz
Wenn Sie bereit sind, Kontexte zu verwenden, kann dies durch Eingabe erreicht werden
Dies zeigt alles zwischen "abc" und "efg" an, solange sie innerhalb von 500 Zeilen voneinander liegen.
quelle
Wenn Sie möchten, dass beide Wörter nahe beieinander liegen, z. B. nicht mehr als 3 Zeilen, können Sie dies tun:
Gleiches Beispiel, aber nur * .txt-Dateien filtern:
Außerdem können Sie den
grep
Befehl durch einenegrep
Befehl ersetzen, wenn Sie auch reguläre Ausdrücke suchen möchten.quelle
Ich habe vor einigen Tagen eine grep-Alternative veröffentlicht, die dies direkt unterstützt, entweder durch mehrzeiliges Matching oder unter Verwendung von Bedingungen - hoffentlich ist es für einige Leute nützlich, die hier suchen. So würden die Befehle für das Beispiel aussehen:
Mehrzeilig:
Bedingungen:
Sie können auch angeben, dass 'efg' innerhalb einer bestimmten Anzahl von Zeilen auf 'abc' folgen muss:
Weitere Informationen finden Sie auf sift-tool.org .
quelle
sift -lm 'abc.*efg' testfile
funktioniert, da das Match gierig ist und alle Zeilen bis zum letztenefg
in der Datei verschlingt .Während die sed-Option die einfachste und einfachste ist, ist der Einzeiler von LJ leider nicht die tragbarste. Diejenigen, die mit einer Version der C-Shell feststecken, müssen ihrem Pony entkommen:
Dies funktioniert bei bash et al. Leider nicht.
quelle
quelle
Sie können grep verwenden, falls Sie nicht an der Reihenfolge des Musters interessiert sind.
Beispiel
grep -l
findet alle Dateien, die mit dem ersten Muster übereinstimmen, und xargs sucht nach dem zweiten Muster. Hoffe das hilft.quelle
Mit Silbersucher :
ähnlich der Antwort des Ringträgers, aber stattdessen mit ag. Geschwindigkeitsvorteile von Silver Searcher könnten hier möglicherweise glänzen.
quelle
(echo abctest; echo efg)|ag 'abc.*(\n|.)*efg'
stimmt nicht übereinIch habe dies verwendet, um eine Fasta-Sequenz aus einer Multi-Fasta-Datei mit der Option -P für grep zu extrahieren:
Der Kern des regulären Ausdrucks ist der,
[^>]
der "nicht größer als das Symbol" bedeutet.quelle
Als Alternative zu Balu Mohan Antwort ist es möglich , die Reihenfolge der Muster nur mit zu erzwingen
grep
,head
undtail
:Dieser ist allerdings nicht sehr hübsch. Lesbarer formatiert:
Dadurch werden die Namen aller Dateien drucken , wo
"pattern2"
nach erscheint"pattern1"
, oder wo beide erscheinen auf der gleichen Linie :Erläuterung
tail -n +i
- Alle Zeilen nach demi
th einschließlich druckengrep -n
- Stellen Sie übereinstimmende Zeilen mit ihren Zeilennummern voranhead -n1
- Nur die erste Zeile druckencut -d : -f 1
- Drucken Sie die erste Schnittspalte:
als Trennzeichen2>/dev/null
- Stummschaltungsfehlerausgabetail
, die auftritt, wenn der$()
Ausdruck leer zurückgegeben wirdgrep -q
- Schweigengrep
und sofort zurückkehren, wenn eine Übereinstimmung gefunden wird, da wir nur am Exit-Code interessiert sindquelle
&>
? Ich benutze es auch, aber ich habe es nirgendwo dokumentiert gesehen. Übrigens, warum müssen wir grep eigentlich so zum Schweigen bringen?grep -q
wird der Trick nicht auch tun?&>
weist bash an, sowohl die Standardausgabe als auch den Standardfehler umzuleiten, siehe REDIRECTION im bash-Handbuch. Sie haben sehr Recht damit, dass wir es genauso gut tun könnten,grep -q ...
anstattgrep ... &>/dev/null
guten Fang zu machen!Das sollte auch funktionieren?!
$ARGV
Enthält den Namen der aktuellen Datei beim Lesen vonfile_list /s
Modifikatorsuchen über Zeilenumbrüche.quelle
Das Dateimuster
*.sh
ist wichtig, um zu verhindern, dass Verzeichnisse überprüft werden. Natürlich könnte auch ein Test dies verhindern.Das
sucht maximal 1 Matching und gibt (-n) die Leinennummer zurück. Wenn eine Übereinstimmung gefunden wurde (test -n ...), finde die letzte Übereinstimmung von efg (finde alle und nimm die letzte mit Schwanz -n 1).
sonst weiter.
Da das Ergebnis so etwas wie ist
18:foofile.sh String alf="abc";
, müssen wir bis zum Zeilenende von ":" wegschneiden.Sollte ein positives Ergebnis liefern, wenn die letzte Übereinstimmung des 2. Ausdrucks nach der ersten Übereinstimmung des ersten Ausdrucks liegt.
Dann melden wir den Dateinamen
echo $f
.quelle
Warum nicht etwas Einfaches wie:
gibt 0 oder eine positive ganze Zahl zurück.
egrep -o (Zeigt nur Übereinstimmungen an, Trick: Mehrere Übereinstimmungen in derselben Zeile erzeugen eine mehrzeilige Ausgabe, als ob sie sich in verschiedenen Zeilen befinden.)
grep -A1 abc
(drucke abc und die Zeile danach)grep efg | wc -l
(0-n Anzahl der nach abc in denselben oder folgenden Zeilen gefundenen efg-Zeilen, Ergebnis kann in einem 'if "verwendet werden)grep kann in egrep usw. geändert werden, wenn ein Mustervergleich erforderlich ist
quelle
Wenn Sie eine Schätzung über den Abstand zwischen den beiden gesuchten Zeichenfolgen 'abc' und 'efg' haben, können Sie Folgendes verwenden:
Auf diese Weise gibt der erste grep die Zeile mit den Zeilen 'abc' plus # num1 danach und den Zeilen # num2 danach zurück, und der zweite grep durchsucht alle Zeilen, um das 'efg' zu erhalten. Dann wissen Sie, bei welchen Dateien sie zusammen erscheinen.
quelle
Mit ugrep vor ein paar Monaten veröffentlicht:
Dieses Tool ist stark auf Geschwindigkeit optimiert. Es ist auch GNU / BSD / PCRE-grep-kompatibel.
Beachten Sie, dass wir eine verzögerte Wiederholung verwenden sollten
+?
, es sei denn, Sie möchten alle Zeilenefg
bis zum letztenefg
in der Datei miteinander abgleichen.quelle
Das sollte funktionieren:
Wenn es mehr als eine Übereinstimmung gibt, können Sie mit grep -v herausfiltern
quelle