Gibt nur den Teil einer Linie nach einem übereinstimmenden Muster zurück

109

Wenn ich also eine Datei mit catund dann mit öffne grep, um übereinstimmende Zeilen zu erhalten, komme ich nur dann weit, wenn ich mit dem bestimmten Protokollsatz arbeite, mit dem ich es zu tun habe. Es ist eine Möglichkeit erforderlich, Linien mit einem Muster abzugleichen, aber nur den Teil der Linie nach dem Abgleich zurückzugeben. Der Anteil vor und nach dem Spiel wird konstant variieren. Ich habe mit sedoder gespielt awk, konnte aber nicht herausfinden, wie die Linie gefiltert werden kann, um entweder den Teil vor dem Spiel zu löschen oder den Teil nach dem Spiel zurückzugeben. Dies ist ein Beispiel für eine Zeile, die ich filtern muss:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

Die Portion, die ich brauche, ist alles nach "ins Stocken geraten".

Der Hintergrund dahinter ist, dass ich herausfinden kann, wie oft etwas stehen bleibt:

cat messages | grep stalled | wc -l

Was ich tun muss, ist herauszufinden, wie oft ein bestimmter Knoten angehalten hat (angezeigt durch den Teil vor jedem Doppelpunkt nach "angehalten") Keine Blockierungen, was mir nicht hilft. Ich muss nur den blockierten Teil filtern, damit ich dann nach einem bestimmten Knoten aus denen suchen kann, die blockiert haben.

In jeder Hinsicht ist dies ein freebsd-System mit Standard-GNU-Kern-Utils, aber ich kann keine zusätzlichen Hilfsprogramme installieren.

MaQleod
quelle
@ Gilles, seltsam, dass das nicht auftauchte, als ich suchte, obwohl ich nicht den Titel benutzte, mit dem ich schließlich ging ... aber er erschien nicht auf dem Bildschirm unter meinem Titel. Abgesehen davon kann es sein, dass ich dahin komme, wo ich will, obwohl ich nach dem Spiel die gesamte Zeile brauche, nicht das erste Wort - aber vielleicht keine große Veränderung.
MaQleod
Sein Titel war scheiße. Ich habe deins gestohlen, was sehr nett ist. Nehmen Sie die sedLösung und behandeln Sie Whitespace nicht speziell.
Gilles
@ Gilles, das ist etwas, bei dem ich mir nicht ganz sicher bin, wie ich es machen soll. Ich lerne immer noch sed.
MaQleod
Ähnlich wie bei unix.stackexchange.com/questions/24089/… .
Tim Kennedy
1
@ shaa0601 Ich verstehe Ihre Frage nicht, es ist besonders schwierig, einem Kommentar ohne Formatierung zu folgen. Stellen Sie eine neue, in sich geschlossene Frage.
Gilles

Antworten:

141

Das kanonische Werkzeug dafür wäre sed.

sed -n -e 's/^.*stalled: //p'

Ausführliche Erklärung:

  • -n bedeutet, dass standardmäßig nichts gedruckt wird.
  • -e wird von einem sed Befehl gefolgt.
  • s ist der Befehl zum Ersetzen von Mustern.
  • Der reguläre Ausdruck ^.*stalled:entspricht dem von Ihnen gesuchten Muster sowie einem beliebigen vorhergehenden Text ( .*dh einem beliebigen Text, mit einer Initiale ^, die besagt, dass die Übereinstimmung am Anfang der Zeile beginnt). Beachten Sie, dass bei stalled:mehrmaligem Auftreten in der Zeile das letzte Vorkommen berücksichtigt wird.
  • Die Übereinstimmung, dh alles in der Zeile bis stalled:, wird durch die leere Zeichenfolge ersetzt (dh gelöscht).
  • Das letzte pMittel zum Drucken der transformierten Zeile.

Wenn Sie den übereinstimmenden Teil beibehalten möchten, verwenden Sie eine Rückreferenz: \1Im Ersatzteil wird angegeben, was sich innerhalb einer Gruppe \(…\)im Muster befindet. Hier könnte man stalled:nochmal in das Ersatzteil schreiben ; Diese Funktion ist nützlich, wenn das gesuchte Muster allgemeiner ist als eine einfache Zeichenfolge.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Manchmal möchten Sie den Teil der Linie nach dem Spiel entfernen. Sie können es in die Übereinstimmung einbeziehen, indem Sie .*$am Ende des Musters einen beliebigen Text .*gefolgt vom Ende der Zeile $einfügen. Wenn Sie diesen Teil nicht in eine Gruppe einfügen, auf die Sie im Ersetzungstext verweisen, wird das Zeilenende nicht in der Ausgabe angezeigt.

Zur weiteren Veranschaulichung von Gruppen und Rückverweisen wird mit diesem Befehl der Teil vor dem Spiel und der Teil nach dem Spiel vertauscht.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'
Gilles
quelle
Ich habe die ersten beiden Beispiele ausprobiert und es scheint nur zu hängen. Ich erhalte weder eine Fehlermeldung noch eine neue Eingabeaufforderung, nur nichts.
MaQleod
2
@MaQleod Oh, es wartet auf die Eingabe über die Standardeingabe. Dies ist das Terminal, da Sie es nicht umgeleitet haben. Hier würden Sie eine Eingabeumleitung durchführen sed … <messages, da Sie Daten aus einer Datei verarbeiten möchten. Zu handeln , auf Daten von einem anderen Befehl erzeugen, dann würden Sie ein Rohr benutzen somecommand | sed ….
Gilles
1
Richtig, dort ist am Ende des Tages ein Stromausfall. Befehl funktioniert einwandfrei, danke.
MaQleod
1
Beste Erklärung, die ich bisher gesehen habe - danke!
Jon Wadsworth
1
@ungalcrys Kürzere Version von was? Dies entspricht keinem der Befehle in meiner Antwort. Ich würde empfehlen , es als zu schreiben , sed 's/^.*stalled//'da -rauf Linux - spezifisch ist und funktioniert nicht auf anderen Systemen wie macOS und hier sind Sie keinen Nutzen daraus zu bekommen.
Gilles
72

Das andere kanonische Tool, das Sie bereits verwenden grep:

Zum Beispiel:

grep -o 'stalled.*'

Hat das gleiche Ergebnis wie die zweite Option von Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

Das -oFlag gibt den --only-matchingTeil des Ausdrucks zurück, also nicht die gesamte Zeile, die normalerweise von grep ausgeführt wird.

Um das "ins Stocken geratene:" aus der Ausgabe zu entfernen, können wir ein drittes kanonisches Werkzeug verwenden:

grep -o 'stalled.*' | cut -f2- -d:

Der cutBefehl verwendet Trennzeichen :und druckt Feld 2 bis zum Ende. Das ist natürlich eine Frage der Präferenz, aber die cutSyntax ist mir sehr leicht zu merken.

Anne van Rossum
quelle
1
Vielen Dank für die Erwähnung der -oOption! Ich wollte darauf hinweisen, dass grepdas nicht \nals Zeilenvorschub erkannt wird, daher stimmt Ihr erstes Beispiel nur mit dem ersten nZeichen überein . Gibt beispielsweise echo "Hello Anne" | grep -o 'A[^\n]*'die Zeichenfolge zurück A. Gibt jedoch echo "Hello Anne" | grep -o 'A.*'das erwartete zurück Anne, da es .mit jedem Zeichen außer der Newline übereinstimmt.
Adamlamar
1
Beachten Sie, dass die Anführungszeichen um das cutTrennzeichen -d':'von @poige entfernt werden. Ich finde es einfacher, mich an Zitate zu erinnern, z . B. an -d' 'oder -d';'.
Anne van Rossum
Nach Ihrer Einschätzung sollte es einfacher sein, sich daran zu erinnern, auch Anführungszeichen -f 2zu verwenden. Ernsthaft, warum nicht?
Poige
Weil ein Trennzeichen wie ein Semikolon ;anstatt eines Doppelpunkts :anders interpretiert wird, wenn es nicht in Anführungszeichen gesetzt wird. Natürlich ist das logisches Verhalten, aber ich verlasse mich trotzdem gerne auf das Muskelgedächtnis. Ich mag es nicht, das Trennzeichen einmal, aber nicht das andere Mal zu zitieren. Nur persönliche Vorlieben, wie ich schon sagte: leichter zu merken.
Anne van Rossum
Der Zeitraum, der Teil der .*ist, wird benötigt, hat für mich gut funktioniert: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' Returnsxyz text
Ron
4

Früher habe ich ifconfig | grep eth0 | cut -f3- -d:dies nehmen

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

und lassen Sie es so aussehen

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8
Luis Perez
quelle
2
Beantwortet dies die Frage?
Stephen Rauch
1
Sie können verwenden cat /sys/class/net/*/address, kein Parsing erforderlich.
Anne van Rossum
1

Ein weiteres kanonisches Tool, das Sie in Betracht gezogen haben, awkkönnte mit der folgenden Zeile verwendet werden:

awk -F"stalled" '/stalled/{print $2}' messages

Ausführliche Erklärung:

  • -Fdefiniert ein Trennzeichen für die Zeile, dh "ins Stocken geraten". Alles vor dem Trennzeichen wird mit angesprochen $1und alles nach mit $2.
  • /reg-ex/ Sucht nach dem passenden regulären Ausdruck, in diesem Fall "ins Stocken geraten".
  • {print $<n>}- druckt eine Spalte. Da Ihr Trennzeichen als blockiert definiert ist, wird alles nach dem Blockieren als zweite Spalte betrachtet.
robertm.tum
quelle