Perl打印到单独的文件

时间:2018-05-09 07:07:48

标签: perl

我有一个列出服务,设备和过滤器的文本文件,这里我只列出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.txtservice2.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

我道歉,我知道这是一个愚蠢的事,但这是一个非常漫长的夜晚,我相信我的大脑无法正常运作。

2 个答案:

答案 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 );
}