我想匹配file1的column3和file2的column2,之后我想在一行中打印匹配行的所有列,我知道如何做到这一点,但问题是如果file2的column2中没有唯一的值那么输出将是 file2 的最后一个匹配行。但我希望单独的文件中存在(冲突的)多个匹配行,并且仅匹配输出文件中的唯一行。
示例:-
我有两个这样的文件:
file1
abc ram_1 ram1
abc ram[0] ram0
bcd raghu_reg_9 raghu9
cde tanu/8 tanu8
file2
1 ram1
2 thakur56
3 ram0
4 ram1
5 ram2
6 raghu9
7 raghu
我尝试使用 awk 作为:
awk 'FNR==NR{a[$2]=$0;next} { if ($3 in a){print a[$3],$1,$2}}' file2 file1
这给出的输出为:
4 ram1 abc ram_1
3 ram0 abc ram[0]
6 raghu9 bcd raghu_reg_9
但我希望输出1为:
3 ram0 abc ram[0]
6 raghu9 bcd raghu_reg_9
在输出2中为:
1 ram1 abc ram_1
4 ram1 abc ram_1
因为文件 2 的第 2 列中有两个 ram1 条目,当我们将文件 1 的第 3 列的 ram1 与文件 2 的第 2 列的 ram1 匹配时,这将匹配两次并将第二个 ram1 作为输出,但我希望如果出现这种类型的情况那么这些冲突的行应该转到单独的文件,以便我可以手动决定应该选择哪一行。
答案1
您可以使用join(1)
将每个匹配键的文件合并为一行:
$ join -1 3 -2 2 -o 2.1,2.2,1.1,1.2 <(sort -k3,3 file1) <(sort -k2,2 file2)
6 raghu9 bcd raghu_reg_9
3 ram0 abc ram[0]
1 ram1 abc ram_1
4 ram1 abc ram_1
其作用是连接文件 1 的字段 3 ( -1 3
) 和文件 2 的字段 2 ( -2 2
) 上的两个文件,输出文件 2 的字段 1 和 2,然后输出文件 1 的字段 1 和 2 ( -o 2.1,2.2,1.1,1.2
)。
连接要求每个输入文件在连接字段上排序,因此<(sort -k3,3 file1)
使用<(sort -k2,2 file2)
“bash(1)
进程替换”来执行并发输入管道并将其提供给连接命令。
通过该输出,您可以用来uniq(1)
提取唯一行和重复行。调用上面的命令joinit
,你可以这样做:
$ joinit | uniq -u -f 1
6 raghu9 bcd raghu_reg_9
3 ram0 abc ram[0]
-u
这会在跳过第一个字段 ( ) 后打印出唯一的行 ( -f 1
)。
$ joinit | uniq -D -f 1
1 ram1 abc ram_1
4 ram1 abc ram_1
-D
这会在跳过第一个字段 ( ) 后打印出所有重复的行 ( ) -f 1
。
要将它们结合在一起并将输出放入output1
和中output2
,您可以通过两个单独的过滤器为管道tee(1)
提供数据:joinit
$ join -1 3 -2 2 -o 2.1,2.2,1.1,1.2 <(sort -k3,3 file1) <(sort -k2,2 file2) \
| tee >(uniq -u -f 1 > output1) | uniq -D -f 1 > output2
同样,这利用了bash(1)
“进程替换”来使并发输出管道将每个管道馈送到不同的uniq
命令。