Unten ist der Text in der Datei:
Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good
Ich muss nach suchen „42B“ und erhalten Sie die Ausgabe aus dem obigen Text wie folgt:
Pseudo name=Apple Code=42B state=fault
Hat jemand eine Idee, wie dies mit grep
/ awk
/ sed
?
Kommentare
- Sie haben diese Frage nur mit " grep " markiert. Suchen Sie dann nur nach " grep " -Lösungen? In der Frage geben Sie auch awk & sed an. Können wir diese Tags hinzufügen? Ich war mir ' Ihrer Absicht nicht sicher, als ich die Frage letzte Nacht bearbeitet habe.
- stackoverflow.com/ Fragen / 12024410 / …
Antwort
Mit awk
awk -v RS="" "/42B/" file
RS=
wird das Trennzeichen für Eingabedatensätze geändert von einer neuen Zeile zu leeren Zeilen. Wenn ein Feld in einem Datensatz /42B/
enthält, drucken Sie den Datensatz.
""
(die Nullzeichenfolge) ist eine Magie Wert zur Darstellung von Leerzeilen gemäß POSIX :
Wenn RS ist null, dann werden Datensätze durch Sequenzen getrennt, die aus einer
<newline>
plus einem oder mehreren Leerzeichen bestehen Zeilen, führende oder nachfolgende Leerzeilen dürfen zu Beginn oder am Ende der Eingabe nicht zu leeren Datensätzen führen, und ein<newline>
muss immer ein Feldtrennzeichen sein, unabhängig vom Wert von FS ist.
Die ausgegebenen Absätze werden nicht getrennt werden, da das Ausgangstrennzeichen eine einzelne neue Zeile bleibt. Um sicherzustellen, dass zwischen den Ausgabeabsätzen eine Leerzeile steht, setzen Sie das Trennzeichen für den Ausgabedatensatz auf zwei neue Zeilen:
awk -v RS="" -v ORS="\n\n" "/42B/" file
Kommentare
- +1 für eine elegante Lösung. Sie müssen die Datei nicht ' umleiten, obwohl …
- Finger auf Autopilot waren.
- @jasonwryan, es sei denn, Sie benötigen Zugriff Für den Dateinamen in awk (
FILENAME
) ist es ' keine schlechte Idee, die Umleitung zu verwenden, da dies Probleme für Dateinamen mit=
oder beginnend mit-
(oder-
) führt zu konsistenten Fehlermeldungen und Vermeidet das Ausführen vonawk
oder das Ausführen anderer Umleitungen, wenn die Eingabedatei ' nicht geöffnet werden kann.
Antwort
Angenommen, die Daten sind so strukturiert, dass es immer die Zeile davor und danach ist, können Sie die -A
(nach) und -B
(vor) wechselt, um anzugeben, dass die 1 Zeile vor dem Spiel und die 1 Zeile danach eingeschlossen werden sollen:
$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
Wenn Sie das möchten Gleiche Zeilen vor und nach dem Suchbegriff können Sie den Schalter -C
(Kontext) verwenden:
$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
If Wenn Sie beim Abgleichen der mehreren Zeilen strenger sein möchten, können Sie das Tool pcregrep
verwenden, um a abzugleichen Muster über mehrere Zeilen:
$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault
Das obige Muster stimmt wie folgt überein:
-
-M
– mehrere Zeilen -
"Pseudo.*\n.*42B.*\nstate.*"
– entspricht einer Gruppe von Zeichenfolgen, wobei die erste Zeichenfolge mit dem Wort"Pseudo"
gefolgt von beliebigen Zeichen bis zum Ende der Zeile\n
, gefolgt von beliebigen Zeichen bis zur Zeichenfolge"42B"
gefolgt von beliebigen Zeichen bis ein weiteres Zeilenende (\n
), gefolgt von der Zeichenfolge"state"
gefolgt von beliebigen Zeichen.
Kommentare
-
-C
(Kontext) kann als Verknüpfung verwendet werden, wenn-A
und-B
identisch sind. - @DavidBaggerman – danke. Fügte es der Antwort hinzu.
- Warum die eine Abstimmung? Dies beantwortet die Frage.
Antwort
Die grep
von Einige Unix-Varianten haben das Flag -p
für „Absatz“. Ich weiß, dass AIX dies tut .
grep -p 42B <myfile>
würde genau das tun, wonach Sie dort fragen YMMV und GNU grep haben dieses Flag nicht.
Kommentare
- Es wäre wunderbar, das Flag -p zu haben. Insbesondere wenn es zusammen mit -v verwendet wird, können Sie ganze Absätze von der Ausgabe ausschließen.
Antwort
Es gibt wahrscheinlich einen ähnlich einfachen Weg, dies mit awk zu tun, aber in Perl:
cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;"
Das bedeutet im Grunde, die Datei in durch Leerzeilen begrenzte Blöcke aufzuteilen und dann nur die Blöcke zu drucken, die Ihrem regulären Ausdruck entsprechen.
Kommentare
- Dies kann vereinfacht werden, indem Optionen und Kurzzeichen verwendet werden und die nutzlose Verwendung von ;
perl -00 -ne 'print if /42B/' file
Antwort
Eine andere Perl-Lösung ohne a Nachgestellte Leerzeile:
perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo
Beispiel
% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good
Kommentare
- Oder kürzer (und damit besser lesbar), wie Triplee in einem Kommentar schrieb:
perl -00 -ne 'print if /42B/' file
.