Trennzeichen zwischen Aussagen in awk

7

Aus Gawks Handbuch:

Wenn awk-Anweisungen innerhalb einer Regel kurz sind, möchten Sie möglicherweise mehr als eine davon in eine Zeile einfügen. Dies wird erreicht, indem die Anweisungen durch ein Semikolon (';') getrennt werden. Dies gilt auch für die Regeln selbst. Daher könnte das am Anfang dieses Abschnitts gezeigte Programm auch folgendermaßen geschrieben werden:

/12/ { print $0 } ; /21/ { print $0 }

HINWEIS: Die Anforderung, dass Regeln in derselben Zeile mit einem Semikolon getrennt werden müssen, war nicht in der ursprünglichen awk-Sprache. Es wurde hinzugefügt, um die Übereinstimmung mit der Behandlung von Aussagen innerhalb einer Aktion zu gewährleisten.

Aber ich habe von https://stackoverflow.com/q/20262869/156458 gesehen

awk '$2=="no"{$3="N/A"}1' file

Sind nicht $2=="no"{$3="N/A"}und 1zwei Aussagen? warum sind sie nicht durch irgendetwas getrennt?

Vielen Dank.

Tim
quelle

Antworten:

10

Sehr gute Frage! Ich denke, der Schlüssel ist folgender: "Somit könnte das am Anfang dieses Abschnitts gezeigte Programm auch so geschrieben werden:"

Ist nicht zwingend erforderlich, um auf diese Weise geschrieben zu werden. Es ist eine Art alternativer Weg. Dies bedeutet (und wurde in Aktion bewiesen), dass die folgenden Aussagen beide korrekt sind:

$ awk '/12/ { print $0 } /21/ { print $0 }' file
$ awk '/12/ { print $0 } ; /21/ { print $0 }' file

Ich denke, diese Semikolonverwendung soll wirklich kurzen, idiomatischen Code abdecken, zum Beispiel Fälle, in denen wir den Aktionsteil weglassen und mehrere Regeln auf dieselbe Zeile anwenden möchten:

$ awk '/12//21/' file
awk: cmd. line:2: /12//21/
awk: cmd. line:2:         ^ unexpected newline or end of string

In diesem Fall muss ein Semikolon verwendet werden, um Regeln (= Bedingungen) zu trennen:

$ awk '/12/;/21/' file

Da das {action}Teil in beiden Regeln / beiden Bedingungen ausgelassen wird, wird die Standardaktion für jede Regel = ausgeführt{print $0}

George Vasiliou
quelle
Ich glaube, dass (für Aktionsmusterlisten): Das Semikolon nach einer Aktionsschließklammer ist optional.
Isaac
gute antwort, aber ich bin mir nicht sicher, ob das '/12/;/21/'alles so üblich ist wie awk idiom. IMO & IME ist es üblicher, so etwas zu schreiben als '/12|21/'- effizienter auch, nur ein regulärer Ausdruck statt zwei oder mehr.
Cas
@cas Die Verwendung von /12/;/21/ist ein vereinfachtes Beispiel, um zu demonstrieren, warum Semikolon erforderlich ist, um Regeln / Bedingungen zu trennen. Für einfache Aufgaben haben Sie Recht, wir können nur einen regulären Ausdruck verwenden or. Jemand kann diese Syntax "nur Bedingungen" auf kompliziertere Bedingungen erweitern, d awk ' $1==10;$2+$NF<100' file. H. Aber da unter allen Bedingungen die Aktion gleich ist = {print $0}, können wir theoretisch überall OR verwenden:awk '$1==10 || $2+$NF<10' file
George Vasiliou
Ja, ich weiß. das war irgendwie mein Punkt. Es ist nicht sinnvoll, mehrere Anweisungen mit unterschiedlichen Mustern und der gleichen Aktion zu haben. Es ist viel sinnvoller, ein einzelnes Muster mit einem komplexeren regulären Ausdruck und / oder mehreren ODER-Bedingungen zu haben: a || b || c || d || e {action}anstatt a {action}; b {same action}; c {same action again} .... Es ist auch einfacher, eine einzige gemeinsame Aktion für all diese Muster zu ändern. in anderen Worten, während das etwas ist , Sie können tun, es ist auch etwas , das man so gut wie nie zu wollen. Ich dachte, das wäre es wert, zu Ihrer Antwort hinzugefügt zu werden.
Cas
6

In gawk beschreiben diese beiden Zitate aus dem Handbuch das Problem:

Eine Aktion besteht aus einer oder mehreren awk-Anweisungen in geschweiften Klammern ('{…}'). Jede Anweisung gibt eine Aufgabe an. Die Anweisungen werden durch Zeilenumbrüche oder Semikolons getrennt.

Ein Semikolon ist ein " Trennzeichen ", aber kein " Terminator ".
Der einzig gültige Terminator einer Aktion ist eine schließende Klammer ( }).

Daher muss das, was auf eine Aktion folgt, die Klammer ( }) schließt, ein anderes Muster {Aktion} sein

Im "man mawk " gibt es eine andere Beschreibung, die helfen kann zu klären, was awk tun soll:

Anweisungen werden durch Zeilenumbrüche, Semikolons oder beides beendet. Gruppen von Anweisungen wie Aktionen oder Schleifenkörper werden wie in C über {...} blockiert. Die letzte Anweisung in einem Block benötigt keinen Terminator.

Der "Mann nawk " erklärt es so:

Das Muster kommt zuerst und dann die Aktion. Aktionsanweisungen sind in {und} eingeschlossen.

Wenn Sie sich mit Details befassen möchten, lesen Sie die POSIX-Beschreibung :

action           : '{' newline_opt                             '}'
                 | '{' newline_opt terminated_statement_list   '}'
                 | '{' newline_opt unterminated_statement_list '}'
                 ;

Und suchen Sie nach einer "nicht abgeschlossenen" Anweisungsliste.

Oder suchen Sie einfacher nach Aktion zum Lesen:

Jede einzelne Anweisung kann durch eine Anweisungsliste in geschweiften Klammern ersetzt werden. Der Antrag muss sicherstellen, dass Anweisungen in einer Anweisungsliste durch oder Zeichen getrennt sind.

Nochmal: are separated by <newline> or <semicolon> characters

Isaac
quelle
Vielen Dank. Suchen Sie in POSIX nach "Terminator", was zeigt, dass ein Semikolon ein "Terminator", aber kein "Trennzeichen" ist. Ich sehe nicht, dass POSIX "Trennzeichen" definiert.
Tim
@ Tim Suche nach Action und lies.
Isaac
3

Das Semikolon zwischen bedingten Blöcken scheint optional zu sein. Nur die Semikolons zwischen Anweisungen innerhalb von Blöcken scheinen obligatorisch zu sein:

$ echo -e "foo\nbar" | gawk '/foo/ { print "foo found" } /bar/ {print "bar found"}'
foo found
bar found
$ echo -e "foo\nbar" | gawk '/foo/ { print "foo found" }; /bar/ {print "bar found"}'
foo found
bar found
$ echo -e "foo\nbar" | gawk '/foo/ { print "foo found"; print "whee" }'
foo found
whee
$ echo -e "foo\nbar" | gawk '/foo/ { print "foo found" print "whee" }'
gawk: cmd. line:1: /foo/ { print "foo found" print "whee" }
gawk: cmd. line:1:                           ^ syntax error

Wenn jedoch der eigentliche Codeblock zwischen zwei Bedingungen zugunsten der Standardeinstellung (dh {print}) weggelassen wird, wird das Semikolon erforderlich:

$ echo -e "foo\nbar" | gawk '/foo/ /bar/'
gawk: cmd. line:2: /foo/ /bar/
gawk: cmd. line:2:            ^ unexpected newline or end of string
$ echo -e "foo\nbar" | gawk '/foo/; /bar/'
foo
bar
DopeGhoti
quelle
Große Köpfe etwas etwas.
DopeGhoti
1
Ich glaube das: Das Semikolon nach einer schließenden Klammer ist optional.
Isaac