Bedingter Block vs bedingte Anweisung (wenn)

17

Angenommen, ich habe eine Datei:

PRO 1
GLN 5.55112e-17
ILE -6.245e-17
THR 5.55112e-17

Ich möchte, dass jede Zeile mit einer Zahl ungleich 1 in der zweiten Spalte in 0 geändert wird und der Rest beibehalten wird.

Wenn ich eine ifbedingte Anweisung verwende, ist alles in Ordnung:

awk '{if($2!=1){print $1,"0"}else{print $0}}' file
PRO 1
GLN 0
ILE 0
THR 0

Aber wenn ich den bedingten Block verwende, passiert etwas Unerwünschtes:

awk '$2!=1 {print $1,"0"} {print $0}' file
PRO 1
GLN 0
GLN 5.55112e-17
ILE 0
ILE -6.245e-17
THR 0
THR 5.55112e-17

Sie können sehen, was los ist.

  • Wie behebe ich diesen Fehler?
  • Warum tritt dieser Fehler auf?
  • Was ist der Unterschied zwischen einer bedingten Anweisung und einem bedingten Block?
Ooker
quelle

Antworten:

26

In einer ifAussage haben Sie eine else. Wenn ifnicht, wird die elseVerzweigung ausgeführt.

In einer bedingten Anweisung werden beide Aktionen ausgeführt, unabhängig davon, ob die Bedingung wahr oder falsch ist.

Eine einfache Lösung:

$ awk '$2!=1 {print $1,"0";next};{print $0}' file
PRO 1
GLN 0
ILE 0
THR 0

Und Sie können es prägnanter machen:

$ awk '$2 != 1 {print $1,"0";next};1' file
PRO 1
GLN 0
ILE 0
THR 0

Wenn die Bedingung erfüllt ist 1und keine Aktion ausgeführt wird, awklautet das Standardverhalten print. printohne Argument wird $0standardmäßig gedruckt .

cuonglm
quelle
4
Sie könnten auch Golf spielen awk '$2!=1?$2=0:"";1' file.
Terdon
@terdon: Gutes Golfen. Ich denke, es kann schwierig sein, dies zu verstehen.
Donnerstag,
1
@ Cuonglm könntest du bitte die Rolle von erklären next. Ich vermute, es unterdrückt den zweiten Ausdruck, wenn der erste wahr ist. So etwas wie continuein C.
Alexander Cska
@Alexander Cska: nextunterdrückt die Verarbeitung der aktuellen Eingabezeile, springe zur nächsten. Die gleiche Rolle wie while, aber für das gesamte awkProgramm. Auch awkhat seine eigenewhile
cuonglm
10

Der zweite Block in

awk '$2!=1 {print $1,"0"} {print $0}' file

ist nicht bedingt. Es wird für jede Zeile ausgeführt und gibt somit jede Zeile aus.

Schreiben Sie stattdessen:

awk '$2!=1 {print $1,"0"} $2==1 {print $0}' file

Oder schreiben:

awk '$2!=1 {print $1,"0"; next} {print $0}' file

Dadurch wird der unbedingte Block übersprungen, wenn der bedingte Block übereinstimmt.

Kyle Jones
quelle