awk-Systemaufruf mit invertiertem Effekt

Ich habe eine Datendatei mit mehreren Datenblöcken, die zwischen bestimmten Schlüsselwörtern eingeschlossen sind (DATA , END). Ich verwende awk, um die Datenblöcke basierend auf einem Dateinamen aus diesem Block in separate Dateien zu extrahieren. Da einige Datenblöcke denselben Namen haben, benenne ich jede Ausgabedatei mit einer ansteigenden Ganzzahl um, wenn die Datei („blockname„) bereits vorhanden ist:

#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4 

Es werden voraussichtlich drei Ausgabedateien blockname1, blockname2 und (beachten Sie, wie der letzten Datei eine Ganzzahl zugewiesen wurde)

#cat blockname1 DATA blockname1 data1 data1 END 

(die anderen entsprechend …)

Jetzt funktioniert das folgende Skript so, wie ich es möchte:

awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file 

Mein Problem liegt in der while -Schleife und sein Systemaufruf:

Ich habe erwartet, dass system("test -e " file) WAHR ist, wenn die file existiert, und FALSCH ist, wenn file existiert noch nicht, dh die while -Schleife startet nur, wenn file vorhanden ist und zu brechen, wenn (die neue) file noch nicht existiert.

Wenn ich jedoch (und machen Sie es ausführlich mit print file), ich habe eine Endlosschleife mit demselben Namen mit zunehmendem Integer-Suffix und dem entgegengesetzten system("test !-e " file) liefert das gewünschte Ergebnis.

Dies verhält sich also genau umgekehrt zu dem, was ich erwartet habe.

Antwort

OK, ich dachte mir: Das Problem liegt in den unterschiedlichen Definitionen von TRUE und FALSE zwischen dem Exit-Status von test und while Schleifenbedingung in awk.

Ein postiver test Befehl führt zu einem Exit-Code von 0 für TRUE und eine negative in 1 für FALSE.

In awk Die Schleife while interpretiert 0 als FALSE und 1 als TRUE, also genau das Gegenteil Definition.

Als Beispiel:

awk "{ while ( 0 ) ; { print "0" } }" file 

wird nicht pro Führen Sie eine Ausgabe aus, während

awk "{ while (1) ; { print "1" } }" file 

unendlich 1 s ausgibt.

Best Practice ist daher in einer solchen Kombination explizit

while ( system("command") == 0 ) 

bzw.

while ( system("command") == 1 ) 

.

In meinem Fall

while ( system("test -e " file ) == 0 ) 

zeigt das erwartete Verhalten.

Antwort

awk system() gibt einen Beendigungsstatus des von Ihnen ausgeführten Befehls zurück – 0 für Erfolg und! = 0 wenn kein Erfolg. Als einfaches Beispiel können Sie versuchen, Folgendes auszuführen:

v = system("date"); 

v ist 0

, wenn Sie Folgendes ausführen:

v = system("dat"); 

v ist möglicherweise 127 oder ein anderer Wert als 0, der vom Betriebssystem zurückgegebene Fehler, wenn der Befehl dat fehlt oder nicht gefunden wird.

Antwort

Wenn ich Sie verstehe, besteht das Ziel darin, den Inhalt der Eingabedatei in verschiedene Dateien zu extrahieren, um zu vermeiden, dass gleichnamige Blöcke verloren gehen.

Wenn dies der Fall ist Wenn das Zielverzeichnis vor der Extraktion immer leer ist, gibt es eine bessere (und schnellere) Lösung:

awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file 

Auf diese Weise funktioniert awk nicht „Sie müssen keine neue Shell N-mal ausführen, um zu testen, ob eine Datei vorhanden ist.

Hinweise:

  • Der BEGIN-Block ist nicht erforderlich, da das Feldtrennzeichen von awk vorhanden ist Es gibt bereits Leerzeichen.
  • Das "\" am Ende der Zeilen ist nicht erforderlich, da das einfache Anführungszeichen bereits mehrzeilig ist.

Kommentare

  • Nun, mein Problem war mehr im Verständnis der “ ungeraden “ Verhalten der while Bedingung. Ihre Lösung ist jedoch ziemlich ordentlich – danke, ich bevorzuge dies gegenüber meinem sperrigen Ding. Der BEGIN-Block ist ein Überbleibsel aus meinem anderen Dateiformat – ich habe vergessen, dass er in meinem allgemeinen Beispiel unbrauchbar wird. Das Weglassen des Backslash erspart mir einige Probleme. Danke auch dafür. Aber Sie sind genau richtig in Bezug auf die Absicht des Skripts ‚. Können Sie den Teil n = blocks[block]++; file=block (n? "_" n: "") genauer erläutern?
  • Der Algorithmus verwendet ein Array: blocks, das indiziert ist nach Blockname. Ex. In der ersten Instanz von "blockname1": blocks["blockname1"]. Awk finde diesen Index und da er nicht ‚ nicht gefunden wird, wird "" angenommen (auch als Null betrachtet). In awk entspricht n = var++ {n=var;var++}, also n=="" und blocks["blockname1"]==1.Schließlich ist file=block (n? "_" n: "") dasselbe wie {file=block;if(n!="") file+="_" n}.
  • Ich war nicht ‚ Ich weiß nicht einmal, dass ein String eine gültige Indizierungsvariable ist, und diese reduzierte if-Anweisung ist sehr hilfreich, nochmals vielen Dank. Ich ‚ bin traurig, dass ich Ihnen hier nicht die “ akzeptierte Antwort “ geben kann: trotz mir Wenn ich diesen Ansatz anwende, da er meine anfängliche Aufgabe erfüllt, ‚ die obige Frage nicht beantwortet (Interpretation der Bedingung in while-Schleife) – dies würde meinem Verständnis dieser Sites Q widersprechen & Ein System. Trotzdem habe ich viel gelernt – nochmals vielen Dank.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.