Bash 有人可以浏览一下合并多个文件的awk代码吗?

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合并多个(>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.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