Bloqueo condicional vs declaración condicional (si)

17

Digamos que tengo un archivo:

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

Quiero que cada línea que tenga un número desigual a 1 en la segunda columna cambie a 0 y conserve el resto.

Si uso if(es decir, declaración condicional), todo está bien:

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

Pero cuando uso el bloque condicional, sucede algo no deseado:

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

Puedes ver lo que está mal.

  • ¿Cómo soluciono este error?
  • ¿Por qué ocurre este error?
  • ¿Cuál es la diferencia entre una declaración condicional y un bloque condicional?
Ooker
fuente

Respuestas:

26

En una ifdeclaración, tienes un else. Si ifno coincide, la elserama se ejecuta.

En una declaración condicional, ambas acciones se ejecutan, independientemente de que la condición sea verdadera o falsa.

Una solución simple:

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

Y puedes hacerlo más conciso:

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

Cuando la condición es verdadera 1y no hay acción, awkel comportamiento predeterminado es print. printsin argumento se imprimirá $0por defecto.

Cuonglm
fuente
44
También podrías jugar golf awk '$2!=1?$2=0:"";1' file.
terdon
@terdon: buen golf. Creo que puede ser difícil para OP entender eso.
Cuonglm
1
@cuonglm, ¿podría explicar el papel de next. Supongo que suprime la segunda impresión si la primera es verdadera. Algo así como continueen C.
Alexander Cska
@Alexander Cska: nextsuprime el procesamiento de la línea de entrada actual, salte a la siguiente. El mismo papel que while, pero para todo el awkprograma. Además, awktiene su propiowhile
Cuonglm
10

El segundo bloque en

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

no es condicional Se actúa sobre cada línea y, por lo tanto, imprime cada línea.

En cambio, escribe:

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

O escribe:

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

Esto hará que se omita el bloque incondicional, si el bloque condicional coincide.

Kyle Jones
fuente