2

From this question, I answer with this solution:

awk 'FNR==NR{a[FNR]=$2;next}{$NF=a[FNR]}1' file2 file1

It works as expected.

But the first solution I thought is:

$ awk 'FNR==NR{a[FNR]=$2;next}$NF=a[FNR]' file2 file1
A 63 9 6
B 45 3 5

It does not work, since when awk had not print the first line in file1. It make me suprise, and don't know why awk skip the first line.

Here is some examples:

$ awk 'FNR==NR{next}$1=123' file2 file1 
123 23 8 T
123 63 9 9
123 45 3 J  

$ awk 'FNR==NR{a[FNR]=$2;next} FNR in a' file2 file1
A   23  8   T
A   63  9   9
B   45  3   J

You can see, from both examples, awk works as expected. First assigning new value to a field of current record affected record value, and awk print new value. The second show that awk had process all record in file2, no record is skipped.

Why awk skip the first line in my first solution?

I use gawk 4.0.1, and also tested with mawk 1.3.3.

9

You have:

$NF=a[FNR]

as the final condition (the one that determines whether to print). Assignments return the value assigned, in this case a[FNR]. The first line of the data file from the linked question is:

A   0

a[FNR] is initialised to $2. That means the value of a[FNR] is 0, which is a false value to awk. That means the assignment is false, which makes the conditional false and suppresses the default printing behaviour. If we change the data file to:

A   1
A   6   
B   0

then the first line will be printed, but the last one will be missing.

So it's not that the first line is absent, it's any line where the last field is zero (or empty). It just happens that the first line and only the first line was like that.

  • I think "Assignment return the value assigned" is not correct, see my own answer. – cuonglm Jul 21 '14 at 9:26
  • Try it: awk 'm=n=0 ; END {print m}' file prints a single 0, because n=0 returned 0. As a condition that's false. Make it 2 and every line prints plus a 2 at the end. – Michael Homer Jul 21 '14 at 9:40
  • No, as the doc said, nothing return from expression pattern in boolean context rather than true or false. "That means the assignment is false" is also wrong. Assignment alway success, whether you assign true or false value. – cuonglm Jul 21 '14 at 10:23
  • 2
    "The assignment is false" doesn't mean it fails to occur, it means it is treated as a false test result, which it is because the value is false. (This is also what your answer says, so I have no idea why you're arguing). – Michael Homer Jul 21 '14 at 10:27
  • 1
    Again: awk 'n=(m=5);END{print n}' prints 5. The assignment to m returned the value assigned. Even awk 'END{print (n=1),n}' if you really want to see the result of assignment directly (it prints 1 1). If you prefer, "an assignment expression in rvalue context evaluates to the value assigned". Any expression in boolean context is treated as false if it's 0 or "" and true otherwise. This is exactly what I said and it's also what you said. You said "the result of assignment is 0", I said the return value of the assignment is 0: these are totally synonymous statements. – Michael Homer Jul 21 '14 at 10:49
0

After some research, I found the answer.

First, according to this:

Expression Patterns

An expression pattern will be evaluated as if it were an expression in a 
Boolean context. If the result is true, the pattern will be considered to 
match, and the associated action (if any) will be executed. If the result is 
false, the action will not be executed.

So in my example, $NF=a[FNR] will be considered as an expression pattern. As the doc said, the result of assignment is evaluated to true or false.

In my example, the result of assignment is 0, which is evaluate to false in boolean context, causing the the pattern is considered as not match, no action is executed.

Note for @Michael Homer

Here is a example to show that The assignment to m returned the value assigned. in awk is incorrect.

$ awk 'function test() {a=2} BEGIN{print test()}'
<blank line>

$ perl -e 'sub test {$a=2}; print test'
2

You can see, what assignment return in awk example?

awk 'n=(m=5);END{print n}' prints 5 because of side effect, it's not meaning awk assignment return value.

  • 2
    Michael Horner's statements are correct. In particular, the assignment to m does return the value assigned. Your example shows this — the value of m=5 is 5, which is why 5 is assigned to n and later printed — so I don't understand what you're failing to understand. – Gilles 'SO- stop being evil' Jul 21 '14 at 13:40
  • @Gilles: What my example show? Do you see assignment in my awk test function return anything? Assignment is an expression, so it has its value. Its value is evaluated, not return. – cuonglm Jul 21 '14 at 14:25
  • 5
    If you want to be strict on terminology, the expression m=5 is evaluated; it evaluates to the value 5, or to put it another way it has the value 5. The value is not evaluated. “Return” is usually used for function calls, but any programmer should understand “the expression returns 5” as “the expression evaluates to 5” even when the expression isn't a function call. At most, Michael's post used technically incorrect terminology, but yours is worse in this respect. The expression m=5 has the same value as the expression 2+3. – Gilles 'SO- stop being evil' Jul 21 '14 at 16:16
  • I understood Michael's answer without difficulty. Don't know why you're thinking he's wrong. And to be fair, his answer should be accepted. – stackoverflower Feb 9 '16 at 11:13

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.