I have an awk expression !a[$0]++
and I want to know the exact evaluation order. From the document of awk, ++
is at higher precedence than !
. However, in this example, ++
is in its postfix form (not !++a[$0]
, which as I understand is basically tells awk, "evaluate other parts first, after that evaluate me". In this case, what's the evaluation order?

- 1,776
-
1https://www.gnu.org/software/gawk/manual/html_node/Precedence.html – glenn jackman Jul 07 '20 at 20:47
2 Answers
I suppose we can agree that a[$0]
has the highest precedence here(*), so we can just simplify that as x
.
I'm going to argue that what you read is correct, that ++
has higher precedence than the !
, so these should be equal:
$ awk 'BEGIN{ x=123; tmp = !x++; print tmp, x; }'
0 124
$ awk 'BEGIN{ x=123; tmp = !(x++); print tmp, x; }'
0 124
And indeed they are. !x++
takes the value of x
, returns it and increments afterwards. The returned value 123
is negated, yielding 0
. The incremented value can later be found in x
.
But let's try the other possibility too, that !
binds tighter:
$ awk 'BEGIN{ x=123; tmp = (!x)++; print tmp, x; }'
awk: cmd. line:1: BEGIN{ x=123; tmp = (!x)++; print tmp, x; }
awk: cmd. line:1: ^ syntax error
Well, whoops. Now, that can't work, since !
would first take the value of x
, then negate it, returning 0
. Now ++
is supposed to increment that, and store the result back. But 0
is just a value, not a variable, it cannot be stored to. Hence the error. (Something like (1+2)++
would give the same error.)
Therefore, ++
has a higher precedence, it just has a hidden side effect that is not apparent from the value it returns.
(* the subscription operator doesn't appear in the precedence table in the standard, as opposed to operator precedence tables of C, but if it had lower precedence, the expression really wouldn't work.)

- 138,973
-
1I found the following two examples are more specific:
awk 'BEGIN{ x=0; tmp = !++x; print tmp, x; }'
andawk 'BEGIN{ x=0; tmp = !x++; print tmp, x; }'
. Also I found that I can always consider!x++
as!x
thenx++
and!++x
as++x
then!x
. They always gives the correct result and is easier to understand. – Just a learner Jul 07 '20 at 21:21 -
1@Justalearner, yep, starting with
x=0
makes the difference between pre- and post-increment apparent; and yes, it can help to mentally move them out of the expression. However, if you face something likea++ + ++a
then that doesn't exactly work... (In C, that's not allowed, in awk it might be well-defined, I don't know. But just hope nobody does that in practice.) – ilkkachu Jul 07 '20 at 21:32
A demo:
$ cat file
1 a
2 b
1 c
2 d
3 e
$ awk '!a[$1]++' file
1 a
2 b
3 e
++
happens first. Since it's a post-increment, for the first line, a[$1]++
increments the value of a[1] but returns zero, and the negation flips that to true, and the first line prints. Same with the 2nd line. For the third line, a[1] already has value 1, the post-increment sets the value to 2 and returns 1, which negated is false.
The mawk man page is more clear:
New expressions are composed with the following operators in order of increasing
precedence.
assignment = += -= *= /= %= ^=
conditional ? :
logical or ||
logical and &&
array membership in
matching ~ !~
relational < > <= >= == !=
concatenation (no explicit operator)
add ops + -
mul ops * / %
unary + -
logical not !
exponentiation ^
inc and dec ++ -- (both post and pre)
field $

- 85,964