在将输入文件的字段与分隔符(逗号,冒号,分号...)连接在一起时,我经常使用内联if-then-else语句(...?...:...)
。
典型的用例是使用输入文件的字段构建字符串,并将该字符串存储在数组中,如下所示:
$ cat file
a 1
b 2
a 3
c 1
b 26
c 4
c 2
为了转置此类文件,我使用以下awk脚本:
awk '{a[$1]=a[$1](a[$1]?",":"")$2}END{for(i in a) printf "%s:%s\n",i,a[i]}' file
I was told认为,使用内联if-then-else的这种方式还不够健壮,我应该使用这种方式:
awk '{a[$1]=($1 in a?a[$1]",":"")$2}END{for(i in a) printf "%s:%s\n",i,a[i]}' file
显然,对于这个简单的输入文件,两个脚本的结果是相同的。
那么为什么第二个脚本会更“健壮”?
我实际上是在寻找一个输入示例,该示例会使第一个脚本失败,但不会使另一个脚本失败。
答案 0 :(得分:2)
首先,我猜您在第一个awk单行代码中又添加了一个a[$1]=
。应该是:
awk '{a[$1]=a[$1](a[$1]?",":"")$2}....
我认为您的问题是关于为什么检查$1 in a
比检查a[$1]
更好。两种单线均可为您提供输入。因为字符串串联使a[$1]
成为字符串。对于字符串,如果不为空,则awk会将其评估为true
。也适用于字符串"0"
但是,如果您必须以某种方式将输入作为数字处理以适合所需的输出,则两次布尔检查可能会不同。如果数字为0
,则awk的值将为false
。
看看这个例子:
kent$ awk 'BEGIN{if(0)print "number"; if("0")print "string"}'
string
您看到只打印了后一个。
因此$1 in a
更好,因为无论a[$1]
存储数字还是字符串,它都将始终有效。
但是,如果您在代码中设置了if(a[$1])
,则可以使用a[$1]
检查,并且100%确保boolean a[$1]
会提供您期望的结果。例如,您在代码中进行了字符串串联""$2
。或者您设置类似a[$1]=1
通常$1 in a
更好。
答案 1 :(得分:1)
除了@Kent提到的内容外,还要考虑一般字段可以为空字符串。提示您当前问题的original question I commented on输入了CSV,因此,我们现在再次使用该输入是为了获得比空格分隔更好的可见性:
$ cat file
a,1
b,
a,3
c,
b,26
c,4
c,2
$ awk -F',' '{a[$1]=a[$1](a[$1]?",":"")$2}END{for(i in a) printf "%s:%s\n",i,a[i]}' file
a:1,3
b:26
c:4,2
$ awk -F',' '{a[$1]=($1 in a?a[$1]",":"")$2}END{for(i in a) printf "%s:%s\n",i,a[i]}' file
a:1,3
b:,26
c:,4,2