Bloc conditionnel vs instruction conditionnelle (si)

18

Disons que j'ai un fichier:

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

Je veux que chaque ligne qui a un nombre différent de 1 dans la deuxième colonne le change en 0 et garde le reste.

Si j'utilise if(c'est-à-dire une déclaration conditionnelle), tout va bien:

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

Mais lorsque j'utilise le bloc conditionnel, quelque chose de indésirable se produit:

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

Vous pouvez voir ce qui ne va pas.

  • Comment puis-je corriger cette erreur?
  • Pourquoi cette erreur se produit-elle?
  • Quelle est la différence entre une instruction conditionnelle et un bloc conditionnel?
Ooker
la source

Réponses:

26

Dans une ifdéclaration, vous avez un else. Si ifne correspond pas, la elsebranche est exécutée.

Dans une instruction conditionnelle, les deux actions sont exécutées, que la condition soit vraie ou fausse.

Une solution simple:

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

Et vous pouvez le rendre plus concis:

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

Quand la condition est vraie 1 et qu'il n'y a aucune action, awkle comportement par défaut est print. printsans argument s'imprime $0par défaut.

cuonglm
la source
4
Vous pouvez également y jouer au golf awk '$2!=1?$2=0:"";1' file.
terdon
@terdon: Bon golf. Je pense qu'il peut être difficile pour OP de comprendre cela.
cuonglm
1
@cuonglm pourriez-vous s'il vous plaît expliquer le rôle de next. Je suppose que cela supprime la deuxième impression si la première est vraie. Quelque chose comme continuedans C.
Alexander Cska,
@Alexander Cska: nextsupprime le traitement de la ligne d'entrée actuelle, passez à la suivante. Le même rôle que while, mais pour l'ensemble du awkprogramme. Aussi, awka sa proprewhile
cuonglm
10

Le deuxième bloc

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

n'est pas conditionnel. Il est appliqué pour chaque ligne et imprime ainsi chaque ligne.

Au lieu de cela, écrivez:

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

Ou écrivez:

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

Cela entraînera le saut du bloc inconditionnel, si le bloc conditionnel correspond.

Kyle Jones
la source