我有一个相对较小的空格分隔文件,看起来像这样(但有很多列和行):
文件1:
Entry1
a
b
c
d
另一个巨大的制表符分隔文件,每行有许多重复的条目,如下所示:
文件2:
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
1 d aaaa4
我试图首先打印一个与 file1 大小相同的制表符分隔文件,指定 file1 中的每个条目与 file2 中的 ID1 字段(第 2 列)之间的匹配,如下所示这是一个单独的问题:
Entry1
a
b
NoMatch
d
并且还打印一个合并的制表符分隔文件,其中包含 file1 和 file2 的值,这次如果 file2 中有重复条目,但也保留 NoMatch,如下所示:
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
NoMatch NoMatch NoMatch
1 d aaaa4
我尝试使用 join 命令给我一条 NoMatch 消息:
join -a1 -e "NoMatch" <(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) <(cat file2 | sort -k1,1) > out.txt
但我一定做错了什么,因为这会打印 file1 的所有内容,但如果 file2 中没有匹配项,则其余字段为空(因此不会出现消息“NoMatch”),您能帮我理解我是什么吗做错了吗?
非常感谢!
#
谢谢吉尔斯,我似乎无法回答你的评论,因为我刚刚注册......你的建议是:
join -a1 -e "NoMatch" -11 -22 --header -o2.1,2.2,2.3 file1 file2
解决了第二个查询Output2,谢谢!我能问一下如何获得第一个Output1,与file1具有相同的行吗?再次感谢!!
在 don_crissti 的帮助下,我可以获得这样的第二个输出:
paste -d'\t' file2 <(awk 'FNR==NR{seen[$1]++; next} {(FNR==1 || ($1 in seen)) || $1="NoMatch"};1' file2 file1)
答案1
重新格式化原始示例以提高可读性:
join -a1 -e "NoMatch" \
<(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) \
<(cat file2 | sort -k1,1)
所有问题都与 file2 处理和join
选项有关。
- file2 按字段 1 排序,应该是字段 2。
- 没有
-t '<tab>'
选项join
,file2 是制表符分隔的。 - 缺少
join
加入 file2 字段 2 的选项。 - 即使 file2 的字段正确
join
,默认输出也会首先打印连接字段,因此您必须指定-o FORMAT
上的选项join
。 - file2 标头未删除。
- 不会引起问题,但不需要处理:
tail
在 file1 上不需要,因为awk
可以跳过第一行。 - 不需要的
-F ' '
选项awk
。
纠正这些问题,结果如下:
#!/bin/bash
head -1 file2
join -t ' ' -2 2 -a 1 -e NoMatch -o 2.1,2.2,2.3 \
<(awk 'NR==1{next} {print $0}' file1.txt | sort) \
<(tail -n +2 file2 | sort -k2)
这会产生以下制表符分隔的输出:
value ID1 ID2
1 a aaaa1
1 a aaaa2
1 b bbbb1
1 b bbbb2
1 b bbbb3
NoMatch NoMatch NoMatch
1 d aaaa4