我目前正试图在perl脚本中合并两个不同的文本文件,但这比这要复杂一些。
问题(为了便于解释,稍作改动):
我有两个不同的文本文件,一个名为dog1.txt
,一个名称为dog2.txt
(如下所示)。
dog1.txt
poodle 8888
jackrussel 5743
beagle 6784
dog2.txt
spaniel 9843
poodle 3756
germanshepard 3267
beagle 3478
正如你所看到的,贵宾犬和比格犬都包含在两个文本文件中,但它们有不同的四位数代码。
我想要的是创建一个新文件,将这两个文件合并在一起。如果有任何重复的文件,如贵宾犬和小猎犬,我希望新文件包含与贵宾犬和比格犬相关的四位数字,来自dog.txt文件,而不是dog2.txt。
新文件需要看起来像这样(这与狗名的顺序无关,与它们相关的数字需要正确):
final_dog.txt
poodle 8888
germanshepard 3267
jackrussel 5743
beagle 6784
spaniel 9843
我尝试过许多不同的解决方案,但没有一个能可靠地按照我需要的方式工作
非常感谢任何帮助,谢谢
您基本上想要打印遇到的第一个实例。因此,您可以使用标准习语来删除重复项。
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
作为一行:
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 join "t", $_, $d{$_} for keys %d; # tab separated
printf "%-20s %sn", $_, $d{$_} for keys %d; # fixed width
请注意,这是一个破坏性的解决方案,不像池上春树的答案那样保留了原始格式。
这个解决方案满足了您的要求,此外,它还满足了每行上的值可能包含空格的情况。
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 $valn";
}
输出
poodle 8888
spaniel 9843
germanshepard 3267
beagle 6784
jackrussel 5743