GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Vorherige Zeile drucken, wenn die Bedingung erfüllt ist

Eine weitere Möglichkeit:Datei umkehren und nächste drucken Zeile, wenn die Bedingung zutrifft:

tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac

Zur Allgemeingültigkeit

Ich denke, es muss erwähnt werden, dass die allgemeinste Lösung für diese Klasse von Problemen zwei Durchgänge beinhaltet:

  • der erste Durchgang zum Hinzufügen einer dezimalen Zeilennummer ($REC) am Anfang jeder Zeile, wodurch Zeilen effektiv nach $REC in Datensätze gruppiert werden
  • der zweite Durchlauf zum Auslösen bei der ersten Instanz jedes neuen Werts von $REC als Datensatzgrenze (Zurücksetzen von $CURREC), danach im nativen AWK-Idiom weiterlaufend in Bezug auf die Datensätze, die auf Übereinstimmung mit $CURREC folgen sollen.

In der Zwischendatei wird eine Folge von Dezimalziffern gefolgt von einem Trennzeichen (aus menschlichen Gründen normalerweise ein hinzugefügter Tabulator oder ein Leerzeichen) als Out-of-Band in Bezug auf die Basisdatei analysiert (auch bekannt als konzeptionell abgeschnitten).

Befehlszeilen-Monster einfügen

Selbst wenn Sie sich auf die Befehlszeile beschränken, ist es einfach sicherzustellen, dass die Zwischendatei niemals auf die Festplatte gelangt. Sie müssen nur eine erweiterte Shell wie ZSH (mein persönlicher Favorit) verwenden, die die Prozesssubstitution unterstützt:

paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk 

Machen wir diesen Einzeiler besser geeignet für die Darstellung:

P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk 

Dadurch werden drei Prozesse gestartet:das triviale Inline-AWK-Skript paste , und das AWK-Skript, das Sie wirklich zuerst ausführen wollten.

Hinter den Kulissen, die <() Das Befehlszeilenkonstrukt erstellt eine benannte Pipe und übergibt den einzufügenden Pipe-Namen als Namen der ersten Eingabedatei. Für paste der zweiten Eingabedatei von , geben wir ihr den Namen unserer ursprünglichen Eingabedatei (diese Datei wird also sequentiell parallel von zwei verschiedenen Prozessen gelesen, die zwischen ihnen höchstens einen verbrauchen von der Festplatte lesen, wenn die Eingabedatei kalt ist).

Die magisch benannte Pipe in der Mitte ist ein In-Memory-FIFO, das das alte Unix wahrscheinlich mit einer durchschnittlichen Größe von etwa 16 kB verwaltete (wobei die paste zeitweise angehalten wurden verarbeiten, wenn yourscript.awk Prozess ist träge beim Leeren dieses FIFOs zurück nach unten).

Vielleicht wirft modernes Unix einen größeren Puffer ein, weil es das kann, aber es ist sicherlich keine knappe Ressource, um die Sie sich Sorgen machen sollten, bis Sie Ihr erstes wirklich schreiben erweiterte Befehlszeile mit Prozessumleitung, die diese zu Hunderten oder Tausenden einbezieht :-)

Zusätzliche Überlegungen zur Leistung

Auf modernen CPUs könnten alle drei dieser Prozesse leicht auf separaten Kernen laufen.

Die ersten beiden dieser Prozesse grenzen an das wirklich Triviale:ein AWK-Skript mit einer einzigen Musterübereinstimmung und etwas kleinerer Buchhaltung, das mit zwei Argumenten aufgerufen wird. yourscript.awk wird es schwer fallen, schneller als diese zu laufen.

Was, Ihre Entwicklungsmaschine hat keine leicht belasteten Kerne, um dieses Master-Shell-Master-Lösungsmuster fast kostenlos in der Ausführungsdomäne zu rendern?

Ring Ring.

Hallo?

Hey, es ist für dich. 2018 hat gerade angerufen und will sein Problem zurück.

2020 ist offiziell die Gnadenfrist von MTV:So mögen wir es, Zauberpfeifen umsonst und Kerne umsonst. Ganz zu schweigen von einem bestimmten TLA-Chip-Anbieter, der heutzutage den Raum erschüttert.

Als abschließende Überlegung zur Leistung, wenn Sie den Aufwand für das Analysieren der tatsächlichen Datensatznummern vermeiden möchten:

X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"

Jetzt wird Ihre In-FIFO-Zwischendatei mit nur zwei zusätzlichen Zeichen kommentiert, die jeder Zeile vorangestellt sind ('0' oder '1' und das standardmäßige Trennzeichen, das durch paste hinzugefügt wird ), wobei „1“ die erste Zeile im Datensatz markiert.

Benannte FIFOs

Unter der Haube unterscheiden sich diese nicht von den magischen FIFOs, die von Unix instanziiert werden, wenn Sie einen normalen Pipe-Befehl schreiben:

cat file | proc1 | proc2 | proc2 

Drei unbenannte Pipes (und ein ganzer Prozess, der cat gewidmet ist braucht man nicht einmal).

Es ist fast bedauerlich, dass die wirklich außergewöhnlichen Die Bequemlichkeit der standardmäßigen stdin/stdout-Streams, wie sie von der Shell vorverwaltet werden, verschleiert die Realität, dass paste $magictemppipe1 $magictemppipe2 bringt in 99 % aller Fälle keine zusätzlichen Leistungsüberlegungen mit sich, über die man nachdenken sollte.

"Verwenden Sie die <() Y-Gelenk, Luke."

Ihr instinktiver Reflex zur natürlichen semantischen Dekomposition in der Problemdomäne wird hierdurch immens profitieren.

Wenn jemand den Verstand gehabt hätte, das Shell-Konstrukt <() zu nennen Als YODA-Betreiber an erster Stelle vermute ich, dass es vor mindestens einem soliden Jahrzehnt in den Universaldienst gedrängt worden wäre.


Dies kann ein Weg sein:

$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA

Erklärung

  • $1=="BB" && $2>1 {print f} wenn das 1. Feld genau BB ist und 2. Feld ist größer als 1 , dann drucken Sie f , ein gespeicherter Wert.
  • {f=$1} speichert die aktuelle Zeile in f , damit es beim Lesen der nächsten Zeile zugänglich ist.

Linux
  1. Cat Zeile X bis Zeile Y in einer riesigen Datei?

  2. Zwei Dateien in zwei Spalten drucken?

  3. Vorherige Zeile nach einer Musterübereinstimmung mit Sed drucken?

  4. Busy Box Datei zeilenweise lesen?

  5. Wie kann ich eine Datei von Awk kategorisieren?

So lesen Sie Dateien Zeile für Zeile in Bash

So lesen Sie eine Datei Zeile für Zeile in Bash

AWK-Befehl unter Linux/Unix

unix - teilt eine riesige .gz-Datei zeilenweise auf

Wie drucke ich die letzte Zeile einer gz-komprimierten Datei in der Befehlszeile?

Mac-Adresse in Datei drucken