Awk 我不喜欢呆呆的行为';我不明白

Awk 我不喜欢呆呆的行为';我不明白,awk,gawk,Awk,Gawk,我试图使用gawk 4.1.4计算文件字段12中不同值的数量,并计算每个值出现的次数。我有两个简短的程序,第一个问题给了我不同的答案,我无法解释为什么 {if(a[$12]++==1){count++}} END {print count} …给出了435176的结果,而 {a[$12]++} END {for (i in a){count++};print count} …给出的结果为599845 你能解释一下这种行为,并告诉我哪个值是正确的吗?我在Windows(ezwinport)下运

我试图使用gawk 4.1.4计算文件字段12中不同值的数量,并计算每个值出现的次数。我有两个简短的程序,第一个问题给了我不同的答案,我无法解释为什么

{if(a[$12]++==1){count++}} END {print count}
…给出了435176的结果,而

{a[$12]++} END {for (i in a){count++};print count}
…给出的结果为599845

你能解释一下这种行为,并告诉我哪个值是正确的吗?我在Windows(ezwinport)下运行,字段分隔符为tab

显然第二个似乎是对的! 您已经存储了
计数
,不需要单独的变量

在这两种情况下,您使用
计数
识别唯一事件的方法都是错误的,因为它没有针对每个唯一实例进行跟踪

使用数组本身的值

推导
count

{if(a[$12]++==1){count++}} END {print count}
是错误的,但事实上,只有当
$12
中的字段在
count
变量中第二次被跟踪时,它才使用post increment运算符。因此,您在输出中看到的计数较少

另一方面,

{a[$12]++} END {for (i in a){count++};print count}
几乎是正确的,但是您不需要
count
变量,您已经将它作为值的一部分存储在数组
a
中,由唯一值
$12
索引。执行上述操作也与

{a[$12}++; next} END {for (i in a) print a[i]}
一个小例子来证明这一点

cat file
1 2 3
1 2 3
1 2 1
1 1 1
2 3 1
3 4 1
假设我担心的是唯一实例及其出现次数在
$2
中。做你的第一个例子

awk '{if(a[$2]++==1){count++}}END {for (i in a) print i,a[i],count}' file
1 1 1
2 3 1
3 1 1
4 1 1
查看最后一列中打印的
count
的错误值,如果您能仔细查看,该变量甚至不是跟踪每个实例的计数,而是所有实例的公共变量

第二种方法看起来不错,但将
count
打印为
4
不清楚哪个实例,假设可能发生多个实例及其计数。正确的方法是

awk '{a[$2]++; next}END {for (i in a) print i,a[i]}' file
1 1
2 3
3 1
4 1
这里不是
count
,而是
a[i]
保存第2列中每个唯一值的唯一计数出现次数。

第一个是错误的(逻辑上,而不是语法上,感谢您强调这一事实,@GeorgeVasiliou),因为您需要在
=
之前
+
++a[$1]==1
:

$ awk '{if(++a[$1]==1){count++}} END {print count}' foo
3
哦,是的,我的测试
foo

$ cat foo
1
1
1
2
2
3

这两个代码段的目的都是简单地计算唯一值的数量,同时求和每个值的计数,但不打印它们。@MattWenham:很公平,不要打印它们,只使用数组值。是的,或者可以使用
{if(a[$12]+==0){count++}END{print count}
,但我觉得这稍微难找到代码。好东西!我唯一的问题是,
count
是不需要的,数组值本身就可以让它工作@伊尼安特鲁达。由于在OP中提到了gawk(lol),因此可以通过
length()
{a[$1]+}END{print length(a)}
获得不同值的数量,对吧?这似乎也行得通。我不知道你可以用这种方式在数组上使用
length
,谢谢。OP使用的第一种方法在特定编程逻辑方面是错误的,但在语法方面没有错误。语法
if(a[$12]+==1){count++}
将在每次恰好找到
$12
两次时将
count
增加1。这是因为后增量-
a[$12]
首先由if计算,然后通过
+
操作增加。