合并并打印较小文件和大文件之间的匹配和不匹配值

合并并打印较小文件和大文件之间的匹配和不匹配值

我有一个相对较小的空格分隔文件,看起来像这样(但有很多列和行):

文件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选项有关。

  1. file2 按字段 1 排序,应该是字段 2。
  2. 没有-t '<tab>'选项join,file2 是制表符分隔的。
  3. 缺少join加入 file2 字段 2 的选项。
  4. 即使 file2 的字段正确join,默认输出也会首先打印连接字段,因此您必须指定-o FORMAT上的选项join
  5. file2 标头未删除。
  6. 不会引起问题,但不需要处理:tail在 file1 上不需要,因为awk可以跳过第一行。
  7. 不需要的-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

相关内容