我需要比较两个文件,并根据比较我需要在第一个文件中添加新列。 C 列是主键。
A,B,C,D
1,1990,I001,2473264
2,1991,I002,2473265
3,1992,I004,2473266
4,1993,6050,912432
5,1994,6003,912433
第二个文件
A,B
I001,2.3 GHz
I002,2.3 GHz
I004,2.3 GHz
6050,1.8 GHz
6003,850 MHz
预期产出
A,B,C,D,E
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433
此代码工作正常,但如果记录不匹配,它将跳过第一个文件中的行。但我不希望它被跳过并在该列中附加 0 或 NA。
awk -F, 'NR==FNR{a[$1]=$2;next}a[$3]{print $0","a[$3]}' test2 test1
A,B,C,D
1,1990,I001,2473264
2,1991,I002,2473265
3,1992,I004,2473266
4,1993,6050,912432
5,1994,6003,912433
6,1995,6004,21234
预期输出:
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
答案1
将您的更改awk
为
$ awk -F, 'NR==FNR{a[$1]=$2;next} FNR!=1{print $0","(a[$3]?a[$3]:"NA")}' SECOND FIRST
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,NA
要获得您第一个想要的结果:
$ awk -F, 'NR==FNR{a[$1]=$2;next} FNR!=1{$3=(a[$3]?a[$3]:"NA")","$3; print}' OFS=, SECOND FIRST
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433
6,1995,NA,6004,21234
答案2
awk
如果我们将其修改为,您的程序是正确的无条件地使用
print $0","( a[$3] ? a[$3] : 0 )
而不是使用
print $0","a[$3]
当a[$3]
非零或空时。也就是说,如果a[$3]
字段为零或空,则使用零,否则使用a[$3]
。
换句话说,
awk -F, -v OFS=',' 'FNR==NR { a[$1]=$2; next } FNR > 1 { print $0, (a[$3] ? a[$3] : 0) }' fileB fileA
我们FNR > 1
在这里使用来跳过标题。
使用join
:
$ join -t , -1 3 -o 1.1,1.2,1.3,1.4,2.2 fileA fileB
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
如果文件未按连接键排序,则(在支持进程替换的 shell 中):
$ join -t , -1 3 -o 1.1,1.2,1.3,1.4,2.2 <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
4,1993,6050,912432,1.8 GHz
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
将对这两个文件join
执行操作。INNER JOIN
告诉-t ,
我们join
逗号是字段分隔符,我们选择第三个字段作为第一个文件中的连接键-1 3
(假定第二个文件中的第一个字段是键,除非我们在该文件中使用-2 N
相同的其他字段N
)。
该-o
标志告诉join
我们要在输出中包含哪些字段以及来自哪个文件(表示文件中的x.y
列)。y
x
join
是一个非常快的操作,但是它需要输入文件按连接键排序(我们很幸运看到上面的第一个示例)。上面第二个例子中的最终输出未排序第一的字段,但您可以通过管道将其轻松解决sort -k1,1n
。
对于第二种情况,由于不匹配,
$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -a 1 -e 0 <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
4,1993,6050,912432,1.8 GHz
A,B,C,D,0
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
通过添加,-a 1 -e 0
我们要求join
始终输出第一个文件中的所有字段(-a 1
,并为第二个文件中缺少的每个字段插入零。
正如您所看到的,我们现在得到了正确的结果,但也包含了第一个文件的标头(因为我们要求它)。如果您想从两个文件的数据中删除标题(并对结果进行排序),那么
$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -e 0 -a1 <( tail -n +2 fileA | sort -t, -k3,3 ) <( tail -n +2 fileB | sort ) | sort -k1,1n
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
该命令实际上适用于这两种情况。
答案3
使用GNU join
与扩展数据和第一的输出格式,加上echo
和tail
来替换标头(因为join
会被不一致的标头混淆):
echo A,B,C,D,E
join -t ',' --header --nocheck-order test1 test2 \
-a 1 -e NA -1 3 -2 1 -o 1.1,1.2,2.2,1.3,1.4 | tail -n +2
输出:
A,B,C,D,E
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433
6,1995,NA,6004,21234