Bash 有人可以浏览一下合并多个文件的awk代码吗?
我正在使用awk合并多个(>3)文件,我希望保留标题。我发现以前的一篇文章完全符合我的需要,但我不太明白发生了什么。我希望有人能带我走过它,这样我就可以从中学习!(我试着对原始帖子发表评论,但没有足够的声誉) 此代码Bash 有人可以浏览一下合并多个文件的awk代码吗?,bash,awk,gawk,Bash,Awk,Gawk,我正在使用awk合并多个(>3)文件,我希望保留标题。我发现以前的一篇文章完全符合我的需要,但我不太明白发生了什么。我希望有人能带我走过它,这样我就可以从中学习!(我试着对原始帖子发表评论,但没有足够的声誉) 此代码 awk '{a[FNR]=((a[FNR])?a[FNR]FS$2:$0)}END{for(i=1;i<=FNR;i++) print a[i]}' f* file2.txt: id value2 a 90 b 30 c 20 file3.t
awk '{a[FNR]=((a[FNR])?a[FNR]FS$2:$0)}END{for(i=1;i<=FNR;i++) print a[i]}' f*
file2.txt:
id value2
a 90
b 30
c 20
file3.txt:
id value3
a 0
b 1
c 25
期望输出
merge.txt:
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
同样,这是代码
awk '{a[FNR]=((a[FNR])?a[FNR]FS$2:$0)}END{for(i=1;i<=FNR;i++) print a[i]}' f* > merge.txt
awk'{a[FNR]=((a[FNR])?a[FNR]FS$2:$0)}END{for(i=1;i首先是数据:
file1 file2 file3
NR FNR $1 $2 NR FNR $1 $2 NR FNR $1 $2
================ ================ ================
1 1 id value1 5 1 id value2 9 1 id value3
2 2 a 10 6 2 a 90 10 2 a 0
3 3 b 30 7 3 b 30 11 3 b 1
4 4 c 50 8 4 c 20 12 4 c 25
第一部分:a[FNR]=((a[FNR])?a[FNR]FS$2:$0)
可以写成:
if(a[FNR]=="") # actually if(a[FNR]=="" || a[FNR]==0)
a[FNR]=$0 # a[FNR] is "id value1" when NR==1
else
a[FNR]=a[FNR] FS $2 # a[FNR]="id value1" FS "value2" when NR==5
每个文件有4条记录,即每个文件的最后一条记录上的FNR==4
,尤其是最后一个文件,因为FNR
的值在处理最后一个文件后仍然存在:
END { # after hashing all record in all files
for(i=1;i<=FNR;i++) # i=1, 2, 3, 4
print a[i] # print "id value1 value value3" etc.
}
END{#对所有文件中的所有记录进行散列后
对于(i=1;i)
如果您正在寻找替代方案,这里有一个基于粘贴的解决方案:
paste file1 file2 file3 | awk '{print $1, $2, $4, $6}' OFS='\t'
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
FNR是相对于当前输入文件的记录数。因此,file1、file2等中的行号
是三元运算符,表示如果[FNR]中已经有某个内容,则将当前记录的$2追加到该内容中,否则为null,因此存储整个记录(即$0)
可能有助于解释问题的伪代码:
if a[FNR] != ""
a[FNR] = a[FNR] : FS : $2
else
a[FNR] = $0
您可以看到,在删除第一个文件后,每个记录中的a、b、c可能是x、y、z,而此程序不会在意。它将第二个字段附加到a[2]、a[3]等。您可以使用awk
和pr
来执行此操作:
$ pr -mts$'\t' f1 <(awk '{print $2}' f2) <(awk '{print $2}' f3)
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
该代码有缺陷且不必要地复杂,请改用以下代码:
$ awk 'NR==FNR{a[FNR]=$0; next} {a[FNR] = a[FNR] OFS $2} END{for (i=1;i<=FNR;i++) print a[i]}' file1 file2 file3
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
最后一个脚本将GNU awk用于多维数组,并在输入文件2中将c
更改为x
,以对其进行测试
如果您有问题,请随时提问,但我认为代码非常清楚。该代码不使用或引用id
,它根据行的顺序而不是每行第一个字段的值来执行所有操作。如果您需要检查id
s,因为它们可能在不同的文件中有所不同,那么您需要不同的解决方案n、 啊。很高兴知道。我确实希望程序检查ID。事实证明,对于我正在使用的当前文件,ID是相同的,但将来不会总是这样。如果我想合并引用ID,最好的解决方案是什么?在a[FNR])中替换FNR
?a[FNR]FS$2:$0)
使用$1
?--NVM在下面看到了您的代码。谢谢!仅供参考:默认为选项卡,因此-mts
就足够了。这太好了。谢谢!
$ paste f1 <(awk '{print $2}' f2) <(awk '{print $2}' f3)
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
$ awk 'NR==FNR{a[FNR]=$0; next} {a[FNR] = a[FNR] OFS $2} END{for (i=1;i<=FNR;i++) print a[i]}' file1 file2 file3
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
$ awk 'NR==FNR{a[NR]=$0;next} {a[FNR] = a[FNR] OFS $2} END{for (i=1;i<=FNR;i++) print a[i]}' file1 file2 file3 | column -t
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 20 25
$ awk '
BEGIN { OFS="\t" }
!($1 in a) { ids[++numIds]=$1 }
{ a[$1][ARGIND]=$2 }
END {
for (i=1;i<=numIds;i++) {
id = ids[i]
printf "%s%s", id, OFS
for (j=1;j<=ARGIND;j++) {
printf "%s%s", a[id][j], (j<ARGIND ? OFS : ORS)
}
}
}
' file1 file2 file3 | column -s$'\t' -t
id value1 value2 value3
a 10 90 0
b 30 30 1
c 50 25
x 20