3

I have 2 column file like:

$ cat data
a4 b1
a4 c2
a4 b4
z4 c2

I want to match both columns such as if (column1 = a4 and column2 = b1) OR (column1 = a4 and column2 = c2) then the output in column3 should be

(DESIRED OUTPUT):

a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -

so I tried to incorporate my logic into 1 liner awk:

$ awk '{print $1, $2, (($1 = a4 && $2 = b1) || ($1 = a4 && $2 = c2) ? "a4-matched" : "-")}' data

and I'm getting - for whole column3, I guess I have wrong awk syntax in place, or something else missing -- below is result:

a4 b1 -
a4 c2 -
a4 b4 -
z4 c2 -
6

You were almost there, but you seem to have introduced a syntax error: $1=a4 would not check if the first column is equal to a4, but assign the content of the awk variable a4 (which is undefined and therefore empty) to the first column, thereby overwriting its content (which you already printed, so you didn't notice) and also evaluating to "false" because an uninitialized variable evaluates as "false". The same is true for your other comparisons. That is why you never get the "matched" condition as "true".

With the (small) required corrections, the program would look as follows:

awk '{if (($1=="a4" && $2=="b1") || ($1=="a4" && $2=="c2")) $3="matched"; else $3="-"} 1' data.txt 

It works as follows:

  • For every line, it will check whether the conditions you mention are met, and adds a third column to the line by setting $3 to either - or matched.
  • It will then print the current line including any modifications made. This is the meaning of the seemingly stray 1 outside of the rule block - awk will print the current line including any previous modifications if it encounters a condition that evaluates to "true" outside of a rule.

Note that the above program is written explicitly for ease of understanding and to demonstrate the point. It can be shortened in your case because the condition on $1 is the same for both "allowed" cases of $2:

awk '{if ($1=="a4" && ($2=="b1" || $2=="c2")) $3="matched"; else $3="-"} 1' data.txt

Also note that modifying any field will cause awk to rebuild the line from its individual fields using the output field separator (defaults to one space), so if the input fields were separated by more than one space, the original formatting will be clobbered. If that is an issue, you should go with the "appending" strategy you already chose in the attempt you presented, although you should then print $0, ( your conditional string ) instead of $1, $2, ( your conditional string ).

0
5

You don't need to check $1 twice, check it once since it's the same condition in both cases, and do several checks of $2 for the different options. Note that assigning new fields will cause awk to rebuild the $0 using the default OFS (single space character) which will cause to squeeze consecutive whitespaces into one if there was any in your input.

awk '{ print $0, ($1=="a4" && ($2=="b1" || $2=="c2")?"matched":"-") }' infile
2
  • Yeah I figured it out after I posted Q. But what if in nonmatching fields, print $1 after : would that be like ?"matched":$1
    – Sollosa
    Jul 27 at 16:55
  • 1
    @Sollosa correct, you can print whatever you want Jul 27 at 16:56
4
$ awk '{print $0, ($1=="a4" && ($2 ~ /^(b1|c2)$/) ? "matched" : "-")}' file
a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.