替换写入文件descritor的最后一行

时间:2016-11-15 09:33:50

标签: perl perl-module perl-data-structures

我正在编写一个小的perl程序,我正在检查#start和#end的模式。议程是创建一个单独的文件,其中包含开始和结束模式之间的行。我可以用下面的脚本来做。

#!/usr/bin/perl

    open(INFILE,"<","testcases") || die "Can't open file: $!";
    my $binary;
    my $tccounter=1;

    while(<INFILE>)
    {
    if(/^#start/i)
        {
        open(OUTFILE,">",$tccounter."_case.sh") || die "Can't open file: $!";
        print "start of the script\n";
        next;
        }
    elsif(/^#end/i)
        {

        ################################
        # Want to replace the previously 
        # written line here with some 
        # addtional  customized lines
        ################################

        close(OUTFILE);
        $tccounter++;
        print "End of the script\n";
        print "last line for this testcase is \n $binary\n";
        next;
        }
    else
        {
        $binary=$_ unless(/^\s*$/);
        print  OUTFILE $_;
        }
    }

但我还需要的是识别写入文件的最后一行,然后用一些自定义数据替换该附加行。 例如,在我的例子中,所有文件的最后一行是execute。 我想在所有输出文件中替换“execute”行。 在当前输出文件的最后一行如下:

execute

预期输出文件的最后一行应该是

preline
execute
postline

输入文件(测试用例):

#start
line1
line 2
execute

#end
#start
line3
line 4
execute
#end
#start
line5
line 6

execute
#end
#start
line7
line 8

execute

#end

2 个答案:

答案 0 :(得分:1)

我建议您应该缓冲输出

如果你将每一行推到一个数组而不是打印它,那么一旦看到#end标签,就很容易找到数组中的最后一个非空行并替换它

然后可以打开输出文件并打印数组的内容

这是未经测试的示例

use strict;
use warnings 'all';

open my $fh, "<", "testcases" or die "Can't open input file: $!";

my $n;
my $i;
my $print;
my @buff;

while ( <$fh> ) {

    if ( /^#start/i ) {

        @buff = ();
        $i = undef;
        $print = 1;

        print "start of the script\n";
    }
    elsif ( /^#end/i ) {

        my $file = ++$n . "_case.sh";
        $print = 0;

        unless ( defined $i ) {
            warn "No data found in block $n";
            next;
        }

        splice @buff, $i, 1, "preline\n", $buff[$i], "postline\n";

        open my $fh, ">", $file or die qq{Can't open "$file" for output: $!};
        print $fh @buff;
        close $fh;

        print "End of the script\n";
    }
    elsif ( $print ) {

        push @buff, $_;
        $i = $#buff if /\S/;
    }
}

答案 1 :(得分:0)

我认为鲍罗丁的回答是要走的路(我还没有评论)。

所以通用算法是:

  • 收集完整记录,从开始标记到结束标记
  • 一旦达到结束标记,则处理记录内容。在你的情况下:
    • 找到最后一条非空行并将其与其他人围绕
    • print found line
    • 写出要记录的文件
  • 根据需要重复

我无法使用触发器操作员抵制和重写Borodins解决方案:

use strict;
use warnings;
open(my $in,'<','in.file') || die "Can't open file: $!";
my ($cnt,@rec);
while( <$in> ) {
    push(@rec,$_) if /^#start/i .. /^#end/i; # collect record lines (using flipflop operator)
    if( /^#end/i ) { # end of record reached?
        next if @rec <= 2; # ignore empty records

        # determine index of last nonempty line
        my ($lci) = grep {$rec[$_]=~/\S/} reverse (1..$#rec-1); # ...except markers

        printf "last line for this testcase is \n%s\n", # print find
            splice @rec, $lci, 1, ("preline\n",$rec[$lci],"postline\n"); # surround with pre&post

        # write out result
        open(my $out,'>',++$cnt.'_case.sh') || die "Can't open file: $!";
        $out->print(@rec[1..$#rec-1]); # ...except markers
        $out->close;

        @rec=(); # empty record for next use
    }
}