我目前正在尝试在perl脚本中合并两个不同的文本文件 - 但它有点复杂。
问题(为了便于解释而略有改动):
我有两个不同的文本文件,一个名为dog1.txt
,一个名为dog2.txt
(如下所示)。
dog1.txt
poodle 8888
jackrussel 5743
beagle 6784
dog2.txt
spaniel 9843
poodle 3756
germanshepard 3267
beagle 3478
正如你所看到的那样,poodle和beagle包含在两个文本文件中,但是有不同的四位数代码。
我想要的是创建的新文件将这两个文件合并在一起如果有任何重复项,例如poodle和beagle,我希望新文件包含与poodle和beagle关联的四位数来自dog1 .txt文件而不是dog2.txt。
新文件需要看起来像这样(与狗名称的顺序无关,它与它们相关的数字需要正确):
final_dog.txt
poodle 8888
germanshepard 3267
jackrussel 5743
beagle 6784
spaniel 9843
我尝试了许多不同的解决方案,但没有一种能够按照我需要的方式可靠地工作。
非常感谢任何帮助,谢谢
答案 0 :(得分:4)
您基本上想要打印遇到的第一个实例。因此,您可以使用标准惯用法来删除重复项。
perl -lane'print if !$seen{$F[0]}++' dog1.txt dog2.txt >final_dog.txt
此方法使用最少的内存。它也会尽可能早地开始输出(如果您输出输出,则非常有用)。
要满足新要求,请使用
perl -lane'print if @F==2 && $F[1]=~/^\d+\z/ && !$seen{$F[0]}++' \
dog1.txt dog2.txt >final_dog.txt
答案 1 :(得分:0)
作为一个单行:
perl -MData::Dumper -lwe '
$d = pop; # save filename for later
%d = map split, <>; # process dog1.txt
push @ARGV, $d; # put the second file name back
while (<>) { # add new entries, unless already defined
my ($dog,$num) = split; $d{$dog} //= $num;
}
print Dumper \%d' dog1.txt dog2.txt
<强>输出:强>
$VAR1 = {
'poodle' => '8888',
'spaniel' => '9843',
'germanshepard' => '3267',
'beagle' => '6784',
'jackrussel' => '5743'
};
此解决方案使用菱形运算符@ARGV
对<>
中的参数进行隐式打开。 //=
已定义或赋值运算符不会覆盖已定义的值。
正如ikegami巧妙地指出的那样,通过反转参数可以消除检查值的必要性。然后这变得非常简单:
perl -MData::Dumper -lwe '
%d = map split, <>;
print Dumper \%d' dog2.txt dog1.txt # note reversed args
我会将print语句留给您,因为您没有指定您的文件是否为制表符分隔符或其他内容。但你可能会这样做:
print join "\t", $_, $d{$_} for keys %d; # tab separated
printf "%-20s %s\n", $_, $d{$_} for keys %d; # fixed width
请注意,这是一种破坏性的解决方案,与ikegami的答案不同,后者保留了原始格式。
答案 2 :(得分:-1)
此解决方案可以满足您的要求,此外它还适用于每行的值可能包含空格的情况。
use strict;
use warnings;
my %data;
for my $file (qw/ dog2.txt dog1.txt /) {
open my $fh, '<', $file or die $!;
while (<$fh>) {
$data{$1} = $2 if /(\S+)\s+(\S(?:.*\S)?)/;
}
}
while (my ($key, $val) = each %data) {
print "$key $val\n";
}
<强>输出强>
poodle 8888
spaniel 9843
germanshepard 3267
beagle 6784
jackrussel 5743