-1

I am writing a small perl program where I am checking the pattern of #start and #end. The agenda is to create a separate file with the lines in between start and end patterns. This I am able to do with below script.

#!/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 $_;
        }
    }

But what I additionally needed is is identify the last line that is being written to a file and then replace that additional line with some custom data. For example, here in my case the last line for all the files is execute. I want replace the line "execute" in all the output files. In the current output files last line is as below:

execute

expected out files last line should be

preline
execute
postline

Input file (testcases):

#start
line1
line 2
execute

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

execute
#end
#start
line7
line 8

execute

#end
user1939168
  • 547
  • 5
  • 20
  • 2
    It is *essential* that you `use strict` and `use warnings 'all'` at the top of every Perl program you write. There is little point in declaring your variables with `my` without `use strict` in place. – Borodin Nov 15 '16 at 09:49

2 Answers2

1

I suggest that you should buffer your output

If you push each line to an array instead of printing it then, once the #end tag is seen, it is simple to locate the last non-blank line in the array and replace it

Then the output file can be opened and the contents of the array printed to it

Here's an untested example

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/;
    }
}
Borodin
  • 126,100
  • 9
  • 70
  • 144
0

I think Borodins answer is the way to go (I'm just not able to comment yet).

So the general algorithm is:

  • collect full record, from start marker to end marker
  • once end marker is reached, process record content. In your case:
    • find last non-empty line and surround it with others
    • print found line
    • write out file for record
  • repeat as needed

I couldn't resist and rewrote Borodins solution using the flipflop operator:

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
    }
}
SREagle
  • 251
  • 2
  • 7