linux 根据特定匹配合并两个文件

iswrvxsc  于 2023-05-06  发布在  Linux
关注(0)|答案(3)|浏览(149)

我有两个大文件,其中每一列由一个制表符分隔。
文件1:

ID1 -5.1 -4.4
ID2 -6.2 -3.8
ID3 -8.9 -7.1
ID4 -14.6 -7.8

文件2:

ID3 apple car joy block,use foo G27H1
ID1 juice mouse,elephant sad,lazy ill,safe bar F25B9
ID5 salt house,room end,thing,else common foobar A30B5,C76D3

我想要的是一个bash脚本,它根据第1列比较两个文件,如果找到匹配项,则将File2的第2、5和7列追加到File1,否则如果没有找到匹配项,则打印“NO MATCH”。这是我的预期输出:

ID1 -5.1 -4.4 juice ill,safe F25B9
ID2 -6.2 -3.8 NO MATCH
ID3 -8.9 -7.1 apple block,use G27H1
ID4 -14.6 -7.8 NO MATCH

这就是我尝试过的:
awk 'FNR==NR{a[$1]=($2,$5,$7);next} END { print($2 in a)} ($1 in a) {print $1,(a[$1])}' $file2 $file1
但我不明白哪里出了问题此外,关于“不匹配”的脚本部分仍然缺失。谁能帮帮我?

jexiocij

jexiocij1#

这里有一个方法来解决这个问题:

$ awk 'NR==FNR{a[$1]=$2 " " $5 " " $7; next}
       {print $0, $1 in a ? a[$1] : "NO MATCH"}' file2 file1
ID1 -5.1 -4.4 juice ill,safe F25B9
ID2 -6.2 -3.8 NO MATCH
ID3 -8.9 -7.1 apple block,use G27H1
ID4 -14.6 -7.8 NO MATCH
66bbxpm5

66bbxpm52#

另一种方法,使用join合并文件中的记录(排序后):

$ join -t ' ' -a 1 -j 1 -o 0,1.2,1.3,2.2,2.5,2.7 -e 'NO MATCH' <(sort file1.txt) <(sort file2.txt) | sed 's/\(NO MATCH *\)\{3\}$/NO MATCH/'
ID1 -5.1 -4.4 juice ill,safe F25B9
ID2 -6.2 -3.8 NO MATCH
ID3 -8.9 -7.1 apple block,use G27H1
ID4 -14.6 -7.8 NO MATCH
8hhllhi2

8hhllhi23#

当前代码有一个与如何将3列分配给数组相关的语法问题:

$ awk 'FNR==NR{a[$1]=($2,$5,$7);next} END { print($2 in a)} ($1 in a) {print $1,(a[$1])}' file2 file1
awk: cmd. line:1: FNR==NR{a[$1]=($2,$5,$7);next} END { print($2 in a)} ($1 in a) {print $1,(a[$1])}
awk: cmd. line:1:                         ^ syntax error

语法问题修复后(例如,a[$1] = $2 OFS $5 OFS $7),当前代码存在几个问题:

  • $1 in a时,代码打印第一个字段($1)而不是整行($0
  • 对于$1 in a为假的行没有处理块,因此没有将NO MATCH附加到所述行的末尾的尝试
  • 不需要END{...}块,因为不需要后文件处理(例如,打印摘要行,转储内存内容等)

解决各种问题的一个awk想法:

awk '
FNR==NR { a[$1] = $2 OFS $5 OFS $7; next }      # append the fields with the output field separator (OFS)
        { ext="NO MATCH"                        # set a default extension
          if ($1 in a)                          # if we have a match in a[] then ...
             ext = a[$1]                        # redefine the extension
          print $0, ext                         # print current row plus extension
        }
' file2 file1

使用三元运算符将后半部分合并为一个print

awk '
FNR==NR { a[$1]=$2 OFS $5 OFS $7; next }
        { print $0, ($1 in a ? a[$1] : "NO MATCH") }
' file2 file1

这两者都产生:

ID1 -5.1 -4.4 juice ill,safe F25B9
ID2 -6.2 -3.8 NO MATCH
ID3 -8.9 -7.1 apple block,use G27H1
ID4 -14.6 -7.8 NO MATCH

备注:

  • OP已经提到输入文件是制表符分隔的
  • 当前输入文件似乎是单空格分隔的
  • 默认的输入字段分隔符(FS =白色)和输出字段分隔符(OFS ==空格)足以生成预期的输出
  • 如果输出需要制表符分隔,则需要更新awk脚本以包含此详细信息,例如:BEGIN { OFS="\t" }BEGIN { FS=OFS="\t" }

相关问题