我在文本文件中设置了以下数据集:
文件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
等于FNR
。NR
为当前输入行号,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
但添加了换行符)当前的第一个字段以及哈希中与其关联的值。