我有一个列出服务,设备和过滤器的文本文件,这里我只列出3个例子:
service1 device04 filter9
service2 device01 filter2
service2 device10 filter11
我编写了一个遍历文件的perl脚本,然后将device=device
filter=filter
打印到根据其所属服务命名的文件中,但如果字符串包含重复的过滤器,则应该将设备添加到同一个文件中,用分号分隔。看一下上面的例子,我需要一个结果:
service1.txt
device=device04 filter=filter9
service2.txt
device=device01 filter=filter2 ; device=device10 filter=filter11
这是我的代码:
use strict;
use warnings qw(all);
open INPUT, "<", "file.txt" or die $!;
my @Input = <INPUT>;
foreach my $item(@Input) {
my ($serv, $device, $filter) = split(/ /, $item);
chomp ($serv, $device, $filter);
push my @arr, "device==$device & filter==$filter";
open OUTPUT, ">>", "$serv.txt" or die $!;
print OUTPUT join(" ; ", @arr);
close OUTPUT;
}
我遇到的问题是service1.txt
和service2.txt
都已创建,但我的结果都错了,请参阅我当前的结果:
service1.txt
device==device04 filter==filter9
service2.txt
device==device04 filter==filter9 ; device==device01 filter==filter2device==device04 filter==filter9 ; device==device01 filter==filter2 ; device==device10 filter==filter11
我道歉,我知道这是一个愚蠢的事,但这是一个非常漫长的夜晚,我相信我的大脑无法正常运作。
答案 0 :(得分:1)
对于每个拥有自己的文件的服务,其中的数据会累积,您需要区分每行要打印的文件。
然后在遇到没有服务的服务时打开一个新的服务文件,这是可行的,因为评论中没有这么多。这可以通过散列服务=&gt;来组织。文件句柄。
use warnings;
use strict;
use feature 'say';
my $file = shift @ARGV || 'data.txt';
my %handle;
open my $fh, '<', $file or die "Can't open $file: $!";
while (<$fh>) {
my ($serv, $device, $filter) = split;
if (exists $handle{$serv}) {
print { $handle{$serv} } " ; device==$device & filter==$filter";
}
else {
open my $fh_out, '>', "$serv.txt" or do {
warn "Can't open $serv.txt: $!";
next;
};
print $fh_out "device==$device & filter==$filter";
$handle{$serv} = $fh_out;
}
}
say $_ '' for values %handle; # terminate the line in each file
close $_ for values %handle;
为了清楚起见,代码在两种情况下的打印几乎相同,肯定可以做得更干净。这仅使用提供的样本数据进行测试,并产生所需的输出。
请注意,当需要评估文件句柄时,我们需要{ }
。例如,请参阅this post。
对原始代码的评论(在上面的代码中解决)
使用词法文件句柄(my $fh
)代替typeglobs(FH
)
除非有特定原因,否则不要立即阅读整个文件
split有很好的默认值split ' ', $_
,其中' '
在空格上分割并丢弃前导和尾随空格。 (在这种情况下,不需要chomp
。)
另一个选择是首先收集每个服务的数据,就像OP尝试一样,但是再次使用散列(service =&gt; arrayref / string with data)并在最后打印。但是我没有理由不打印,因为您需要相同的逻辑来决定何时需要添加;
。
答案 1 :(得分:-1)
你的代码看起来很漂亮,但这不是问题。正如MrTux所指出的那样,你会混淆收集和散布你的数据。我已经重构了这个,使用哈希作为中间容器,服务名称作为键。请注意,这不会在mutliple调用中累积结果(因为它使用“&gt;”而不是“&gt;&gt;”)。
use strict;
use warnings qw(all);
use File::Slurp qw/read_file/;
my @Input = read_file('file.txt', chomp => 1);
my %store = (); # Global container
# Capture
foreach my $item(@Input) {
my ($serv, $device, $filter) = split(/ /, $item);
push @{$store{$serv}}, "device==$device & filter==$filter";
}
# Write out for each service file
foreach my $k(keys %store) {
open(my $OUTPUT, ">", "$k.txt") or die $!;
print $OUTPUT join(" ; ", @{$store{$k}});
close( $OUTPUT );
}