Ich habe eine Reihe von Dateien und möchte herausfinden, welche sequentielle Zeilen enthält, die mit einer bestimmten Zeichenfolge beginnen.
Zum Beispiel für die folgende Datei:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Cyyyyyyyyy
Czzzzzzzzz
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Ceeeeee
Es gibt mehr als eine Zeile, die mit 'C' beginnt, daher möchte ich, dass diese Datei per Befehl gefunden wird.
Zum Beispiel für die folgende Datei:
Aaaaaaaaaaaa
Baaaaaaaaaaa
Cxxxxxxxxx
Abbbbbbbbbbb
Bbbbbbbbbbbb
Caaaaaa
Accccccccccc
Bccccccccccc
Cdddddd
Es gibt immer eine Zeile, die mit 'C' beginnt. Ich möchte diese Datei nicht. Ich dachte an ein grep
oder ein, sed
aber ich weiß nicht genau, wie ich es machen soll. Vielleicht mit einem regulären Ausdruck ^C.*$^C
oder so etwas. Irgendeine Idee ?
C
In Ihrem zweiten Beispiel beginnen zwei Zeilen .C
?grep
Versionen.Antworten:
Mit
pcregrep
:POSIXly:
(Dies bedeutet jedoch, dass alle Dateien mit den
awk
nicht unterstützten Implementierungen vollständig gelesen werden müssennextfile
.)Mit Versionen von GNU
grep
bis 2.5.4:scheint zu funktionieren, aber es ist ein Zufall und es ist nicht garantiert, dass es funktioniert.
Bevor es in 2.6 (durch dieses Commit ) behoben wurde , hatte GNU
grep
übersehen, dass die von ihm verwendete PCRE-Suchfunktion für den gesamten aktuell verarbeiteten Puffer übereinstimmen würdegrep
, was zu allerlei überraschendem Verhalten führte. Zum Beispiel:würde mit einer Datei übereinstimmen, die enthält:
Dies würde passen:
Aber dieses:
Oder:
würde nicht (da das
1\n2\n
über zwei Puffer von verarbeitet wirdgrep
).Dieses Verhalten wurde jedoch dokumentiert:
Nachdem es in 2.6 behoben wurde, wurde die Dokumentation nicht geändert (ich habe es dort einmal gemeldet ).
quelle
exit
und-exec \;
statt nextfile zu verwenden?awk
pro Datei auszuführen . Sie möchten dies nur tun, wennawk
dies nicht unterstützt wirdnextfile
und Sie einen großen Anteil an Dateien haben, die groß sind und am Anfang der Datei übereinstimmende Zeilen aufweisen.-z
werden können-P
. Es gibt kein\N
ohne-P
, Sie müssten es schreiben,$'[\01-\011\013-\0377]'
was nur in C-Gebietsschemas funktionieren würde (siehe thread.gmane.org/gmane.comp.gnu.grep.bugs/5187 )Mit
awk
:Dadurch wird der Inhalt der Datei gedruckt, wenn aufeinanderfolgende Zeilen mit a beginnen
C
. Der Ausdruck untersucht(p ~ /^C/ && $1 ~ /^C/)
aufeinanderfolgende Zeilen in der Datei und wird als wahr ausgewertet, wenn das erste Zeichen in beiden übereinstimmtC
. In diesem Fall wird die Zeile gedruckt.Um alle Dateien mit einem solchen Muster zu finden, können Sie den obigen awk über einen
find
Befehl ausführen :In diesem Befehl durchläuft das
find
+exec
jede der Dateien und führt eine ähnlicheawk
Filterung für jede Datei durch und druckt ihren Namen über,FILENAME
wenn der awk-Ausdruck als wahr ausgewertet wird. Um zu vermeiden,FILENAME
dass eine einzelne Datei mit mehreren Übereinstimmungen mehrmals gedrucktexit
wird, wird die Anweisung verwendet (danke @terdon).quelle
C
flag
, nurexit
stattdessen. Auf diese Weise müssen Sie die Dateien nicht weiter verarbeiten, nachdem eine Übereinstimmung gefunden wurde.Noch eine Option mit GNU
sed
:Für eine einzelne Datei:
(obwohl es auch die Dateien meldet, die es nicht lesen kann).
Für
find
:Das Problem mit unlesbaren Dateien, die gedruckt werden, kann durch Schreiben vermieden werden:
quelle
sed -n '$q1;/^C/{n;/^C/q}'
?$q1
- zwingt sed, mit einem Fehler zu beenden, wenn kein Muster gefunden wird. Es wird auch mit einem Fehler beendet, wenn etwas mit der Datei nicht stimmt (sie ist nicht lesbar oder defekt). Daher wird es nur dann mit dem Beendigungsstatus 0 beendet, wenn ein Muster gefunden wurde, und es wird an den Druck übergeben. Teil mit/^C/{n;/^C/q
ist ziemlich einfach. Wenn eine Zeichenfolge gefunden wird, die mit C beginnt, wird die nächste Zeile gelesen, und wenn sie auch mit C beginnt, wird sie mit dem Beendigungsstatus Null beendet.Angenommen, Ihre Dateien sind klein genug, um in den Speicher eingelesen zu werden:
Erläuterung:
000
:\n\n
Als Datensatztrennzeichen festgelegt, wird der Absatzmodus aktiviert, in dem Absätze (durch aufeinanderfolgende Zeilenumbrüche getrennt) als einzelne Zeilen behandelt werden.-ne
: Wenden Sie das als Argument angegebene Skript-e
auf jede Zeile der Eingabedatei (en) an.$ARGV
: ist die Datei, die gerade verarbeitet wird/^C[^\n]*\nC/
: ÜbereinstimmungC
am Zeilenanfang (siehe die Beschreibung dersm
Modifikatoren unten, warum dies hier funktioniert), gefolgt von 0 oder mehr Nicht-Zeilenumbruchszeichen, einer Zeilenumbruch und einem weiteren C. Mit anderen Worten, finden Sie aufeinanderfolgende Zeilen, die mit beginnenC
. *//sm
: Diese Übereinstimmungsmodifikatoren sind (wie [hier] dokumentiert):Sie könnten auch etwas Hässliches tun wie:
Hier
perl
ersetzt der Code Zeilenumbrüche durch%%
. Vorausgesetzt, Sie haben keine%%
in Ihrer Eingabedatei (groß, wenn natürlich),grep
stimmen die Zeilen mit aufeinanderfolgenden Zeilen überein, beginnend mitC
.quelle
LÖSUNG:
DEMO:
Zuerst erstellen wir eine Testbasis:
Das obige erstellt 26 Dateien in
/tmp
namensfile1-26
. In jeder Datei gibt es 27 oder 28 Zeilen, die mit den Buchstaben beginnena-z
und vom Rest des Alphabets gefolgt werden. Jede dritte Datei enthält zwei aufeinanderfolgende Zeilen, in denen das erste Zeichen dupliziert wird.STICHPROBE:
Und wenn ich mich ändere:
zu:
Ich bekomme...
AUSGABE:
Kurz gesagt, die Lösung funktioniert folgendermaßen:
quelle
Dieses Skript verwendet
grep
undcut
zum Abrufen von Zeilennummern übereinstimmender Zeilen und sucht nach zwei aufeinander folgenden Nummern. Für die Datei wird ein gültiger Dateiname angenommen, der als erstes Argument an das Skript übergeben wird:quelle