我是 awk 编程的新手,正在学习数组的工作原理。我找到了这段代码:
awk 'BEGIN{OFS=FS=","}NR==FNR{a[$1]=$2;next}$3 in a && $3 = a[$3]' filez filex
他们将$1
其作为索引放入数组中,并$2
作为值 then if$3
等于索引 和 for this one $3 = a[$3]
。我不明白这是什么意思,因为第一个文件只有 2 列 -$3
与第二个文件相比,他们在哪里想到的$3
?!?
输入文件filez
:
111,111
112,114
113,113
输入文件filex
:
A,bb,111,xxx,nnn
A,cc,112,yyy,nnn
A,dd,113,zzz,ppp
答案1
该脚本的目的是将第二个文件 ( ) 第三列中的值替换filex
为第一个文件 ( ) 第二列中存储的相应值filez
。
NR
是当前行相对于第一个处理的文件的第一行的行号。它是一个“全局”线路计数器。FNR
是相对于当前处理的文件的开头的当前行号。
NR==FNR
是仅对第一个文件计算为 true 的条件。相应的操作 ( {a[$1]=$2;next}
) 将整个第一个文件逐行放入字典中,字典是a
一个关联数组,其目的是根据第一列中的相应值查找第一个文件第二列的值。next
使awk
跳过剩余条件并重新开始循环,读取下一行。
$3 in a && $3 = a[$3]
是具有潜在副作用的条件(分配给$3
)。仅对第二个文件进行评估(当NR==FNR
为 false 时;请记住,当NR==FNR
为 true 时,$3 in a && $3 = a[$3]
将被跳过)。对于每一行,如果在字典中找到第三个字段的值(作为索引)a
,则将其替换为字典中的相应值。然后,如果$3 = a[$3]
计算结果为 true,则打印该行(因为在 AWK 程序中,基本上由条件(或“模式”)-动作对组成,条件或动作都可以省略,省略的动作相当于print
)。
假设这缩短了filez
:
111,111
112,114
和filex
:
A,bb,111,xxx,nnn
A,cc,112,yyy,nnn
一步一步发生的事情是:
filez
读取的第一行;NR==FNR
计算结果为1==1
,真;因此,{a[$1]=$2;next}
执行 ;a[111]
设置为111
;next
意味着$3 in a && $3 = a[$3]
跳过此行脚本的其余部分(具体来说,$3
暂时不使用);不打印任何内容,因为执行的操作不包含任何打印命令;filez
读取第二行和最后一行;NR==FNR
评估结果为2==2
, true;{a[$1]=$2;next}
被执行;a[112]
被设定为114
;$3 in a && $3 = a[$3]
再次被跳过,因为next
;再次,没有打印任何内容;filex
读取第一行;NR==FNR
计算结果为3==1
, false;因此{a[$1]=$2;next}
是不是被处决;评估下一个条件:$3
是111
且 是 的索引值a
,因此$3 in a
为 true 并$3 = a[$3]
评估;它导致将a[111]
,即111
,分配给$3
;由于111
既不是0
空字符串,条件赋值也计算为 true 并打印当前行;A,bb,111,xxx,nnn
filex
读取第二行和最后一行;NR==FNR
计算结果为4==2
, false;因此{a[$1]=$2;next}
是不是被处决;评估下一个条件:$3
是112
且 是 的索引值a
,因此$3 in a
为 true 并$3 = a[$3]
评估;它导致将a[112]
,即114
,分配给$3
;由于114
既不是0
空字符串,条件赋值也计算为 true 并打印当前行。A,cc,114,yyy,nnn
答案2
BEGIN{OFS=FS=","}
将输入和输出字段分隔符设置为,
。NR==FNR
仅适用于第一个文件。因此,对于第一个文件:a[$1]=$2
$1
将其作为索引和$2
值放入array 中a
。next
跳过该行脚本的其余部分。
再说一遍:next
意思是脚本的其余部分仅针对第二个文件执行(以及第三个、第四个……文件,如果存在的话)。
$3 in a && $3 = a[$3]
如果第三个字段是数组的键a
,则将第三个字段替换为a[$3]
。现在,由于这不是在操作环境中(即不在 inside{}
),这意味着如果两个条件都为真,则应打印当前记录。否则,什么也不能做。
一般来说,由于右侧的条件是赋值,因此如果左侧为 true,则结果为 true。但是,如果分配了空字符串或数字 0,则该分配将被评估为 false。这可能是有意为之,但通常是程序员未能注意到的边缘情况。要查看它,请尝试使用 awk 代码
filez
:
111,111
112,114
113,113
000,000
filex
:
A,bb,111,xxx,nnn
A,cc,112,yyy,nnn
A,dd,113,zzz,ppp
A,ee,000,uuu,aaa
请注意,对于最后一行,虽然$3 in a
为 true,但$3 = a[$3]
分配为 0,因此不会打印该行!
$ awk 'BEGIN{OFS=FS=","}NR==FNR{a[$1]=$2;next}$3 in a && $3 = a[$3]' filez filex
A,bb,111,xxx,nnn
A,cc,114,yyy,nnn
A,dd,113,zzz,ppp
应OP要求澄清:
请记住:该数组填充有a[$1]=$2
在第一个文件中, filez
.
$3 = a[$3]
被执行对于第二个文件, filex
.
例如:在第二行filez
,a[$1]=$2
-> a[112] = 114
。在第二行filex
,$3 = a[$3]
-> 112=a[112]=114
。