我有一个 awk 表达式!a[$0]++
,我想知道确切的求值顺序。从 awk 的文档来看,++
的优先级高于!
.然而,在这个例子中,++
是 的后缀形式(不是!++a[$0]
,据我了解,它基本上告诉 awk,“首先评估其他部分,然后评估我”。在这种情况下,评估顺序是什么?
答案1
我想我们可以同意a[$0]
在这里具有最高优先级(*),所以我们可以将其简化为x
。
我要说你读到的内容是正确的,它的++
优先级高于!
,所以这些应该是相等的:
$ awk 'BEGIN{ x=123; tmp = !x++; print tmp, x; }'
0 124
$ awk 'BEGIN{ x=123; tmp = !(x++); print tmp, x; }'
0 124
确实如此。!x++
获取 的值x
,返回它并随后递增。返回值123
被取反,产生0
。稍后可以在 中找到增加的值x
。
但我们也尝试一下另一种可能性,这种可能性!
结合得更紧密:
$ 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
嗯,哎呀。现在,这是行不通的,因为!
首先会取 的值x
,然后对其取反,返回0
。现在++
应该增加它,并将结果存储回来。但0
它只是一个值,而不是一个变量,它不能被存储。因此出现了错误。 (类似的东西(1+2)++
会给出同样的错误。)
因此,++
具有更高的优先级,它只是有一个隐藏的副作用,从它返回的值来看并不明显。
答案2
演示:
$ cat file
1 a
2 b
1 c
2 d
3 e
$ awk '!a[$1]++' file
1 a
2 b
3 e
++
首先发生。由于它是后递增,因此对于第一行,a[$1]++
递增 a[1] 的值但返回零,并且求反将其翻转为 true,然后打印第一行。与第 2 行相同。对于第三行,a[1]已经有值1,后置增量将值设置为2并返回1,其取反为假。
mawk 手册页更清晰:
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 $