如何合并来自两个不同文本文件的值?

如何合并来自两个不同文本文件的值?

我在文本文件中设置了以下数据集:

文件1.txt

a1:b1
a2:b2
a3:b3
a4:b4
a5:b5

文件2.txt

b2:c1
b4:c2
b5:c3

如何合并这些值以生成如下输出文件:

输出.txt

a2:c1
a4:c2
a5:c3

答案1

由于您的文件似乎包含已排序的数据,因此您应该能够使用该join命令,例如

join -12 -21 -t: -o1.1,2.2 file1.txt file2.txt > output.txt

然后

cat output.txt
a2:c1
a4:c2
a5:c3

请参阅man join以了解选项的详细信息。

如果文件不是预先排序,然后您可以先使用进程替换对它们进行排序。但请注意,排序必须按照要连接文件的字段进行例如

join -12 -21 -t: -o1.1,2.2 <(sort -t: -k2,2 file1.txt) <(sort -k1,1 file2.txt)
androgynous:hu2nt
gra7vel:fi6nal
cosm4etic:citizen

结果也将按排序顺序排列:如果您不想要这样,那么有一种相当标准的方法可以awk使用数组来执行此类操作,例如

awk -F: 'NR==FNR {a[$2]=$1; next;} ($1 in a) {print a[$1]":"$2;}' file1.txt file2.txt

答案2

这里有一种awk方法:

awk -F: '(NR==FNR){a[$2]=$1; next}($1 in a){print a[$1]":"$2};' file1 file2 > out

解释

  • awk -F:运行awk,将字段分隔符设置为:。这将读取每个输入行并将其拆分为:。因此,对于 的第一行file1,第一个字段($1)为a1,第二个字段($2)为b1
  • (NR==FNR){}:若NR等于FNRNR为当前输入行号,FNR为当前文件的行号。只有在读取第一个文件时,两者才会相等。
  • a[$2]=$1; next:将第二个字段作为键保存到数组中,键a为第一个字段的值,然后跳到下一行。
  • ($1 in a){print a[$1]":"$2}:这只会在读取第二个文件时执行。如果第二个文件的第一个字段是键数组a,则打印该键的值(对应行的第二个字段file1)。

还有一个 Perl 的:

perl -F: -lanE '$k{$F[0]} ? say "$k{$F[0]}:$F[1]" : ($k{$F[1]}=$F[0]);' file1 file2 > out

或者,如果你愿意的话:

perl -F: -lanE '$k{$F[0]} and say "$k{$F[0]}:$F[1]" or ($k{$F[1]}=$F[0]);' file1 file2 

解释

  • perl -F: -lanE-n表示“逐行读取每个输入文件,并将 给出的脚本应用于-E每个输入文件”。-E和 一样-e, 允许您在命令行上传递脚本。 不同之处在于-E启用了一些额外的功能,例如say-a启用 给出的字符自动拆分每个输入行-F。 结合起来,它们的perl作用类似于awk。 字段被拆分为数组@F,第一个字段是$F[0],第二个字段是$F[1],依此类推。 最后,从每行末尾-l删除换行符 ( )。\n
  • $k{$F[0]} ? foo : bar:如果变量$k{$F[0]}已定义,则执行 foo,否则执行 bar。
  • ($k{$F[1]}=$F[0]):如果$k{$F[0]}未定义,则会发生这种情况(即上面的“bar”)。它将第二个字段保存为哈希中的键,%k其值是第一个字段。
  • say "$k{$F[0]}:$F[1]"$k{$F[0]}:如果已定义(上面的“foo”),则此操作将运行,因此如果当前行的第一个字段是另一行中的第二个字段。如果是,则打印(say类似print但添加了换行符)当前的第一个字段以及哈希中与其关联的值。

相关内容