21

Say I have a file:

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

I want every line that has a number unequal to 1 in the second column to change it to 0 and keep the rest.

If I use if (i.e conditional statement), everything is OK:

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

But when I use the conditional block, something undesired happens:

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

You can see what's wrong.

  • How do I fix this error?
  • Why does this error occur?
  • What's the different between a conditional statement and a conditional block?
polym
  • 10,852
Ooker
  • 667

2 Answers2

31

In an if statement, you have an else. If if doesn't match, the else branch is executed.

In a conditional statement, both actions are executed, regardless of the condition is true or false.

A simple fix:

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

And you can make it more concise:

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

When condition is true 1 and there is no action, awk default behavior is print. print with no argument will print $0 by default.

cuonglm
  • 153,898
  • 4
    You could also golf it into awk '$2!=1?$2=0:"";1' file. – terdon Jul 10 '14 at 00:55
  • @terdon: Good golfing. I think it can be difficult to OP to understand that. – cuonglm Jul 10 '14 at 02:53
  • 1
    @cuonglm could you please explain the role of next. I guess it suppresses the second print if the first one is true. Something like continue in C. – Alexander Cska Jan 27 '17 at 11:00
  • @Alexander Cska: next suppresses processing current input line, skip to the next one. The same role as while, but for the whole awk program. Also, awk has its own while – cuonglm Jan 27 '17 at 15:07
11

The second block in

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

isn't conditional. It is acted upon for every line, and thus prints every line.

Instead, write:

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

Or write:

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

This will cause the unconditional block to be skipped, if the conditional block is matched.

polym
  • 10,852
Kyle Jones
  • 15,015