Строки печати, за которыми следует строка, соответствующая шаблону, в файл A, если совпадений нет, то печать в файл B

Я пытаюсь написать сценарий Perl для анализа файла и разделения его содержимого на основе критериев соответствия. Образец файла (например, test.txt) будет выглядеть примерно так:

      command something something keyword something something
filepath1
filepath2
command something something something something
filepath3
filepath4
filepath5

Результатом сценария будут два файла, основанные на имени входного файла для сценария, test.keyword и test.nomatch.

test.keyword будет иметь что-то вроде этого:

      command something something keyword something something
filepath1
filepath2

test.nomatch будет примерно так:

      command something something something something
filepath3
filepath4
filepath5

Я пытался найти способы достичь этого, но не могу найти что-то, что мне помогло бы. Это единственная оставшаяся часть моего сценария, которая сводит меня с ума. И да, я не эксперт в Perl. :(

Ниже приведен скелет, который у меня есть в данный момент, который ожидает этого условия золотого цикла:

      #!/usr/bin/perl -a

my $fh = shift or die "No file passed as argument for splitting!\n";
open( infile, "<$fh" ) or die $!;
open( vef_output, ">$fh.vef" ) or die $!;
open( svf_output, ">$fh.svf" ) or die $!;

$mode = 0; #0 for vef and 1 for svf

while ( my $line = <$infile> ) {
        if ( $line =~ /SOME_LIBRARY_OPTIONS/ ) {
        if ( $line =~ /\-sv/ ) {
            print {$svf_output} $line;
            $mode = 1;
        }
        else {
            print {$vef_output} $line;
            $mode = 0;
        }
        next;
    }
    if ( $mode eq 0 ) {
        print {$vef_output} $line;
        next;
    }
    else {
        print {$svf_output} $line;
        next;
    }   
}
close($vef_output);
close($svf_output);
close($file);

2 ответа

Решение

Хотя логика вашего кода верна и вы наверняка сами найдете некоторые оставшиеся опечатки, я хотел бы предложить модификацию вашего цикла while:
каждую строку вашего входного файла нужно будет напечатать один раз (за исключением, возможно, начала входного файла). Вместо того, чтобы устанавливать $mode flag и протестировав это, я бы предпочел переключить дескриптор выходного файла, что приведет к более четкому коду:

      #!/usr/bin/perl
use strict;
use warnings;

my $filename = shift or die "No file passed as argument for splitting!\n";

# add filename to error message - users will like it!
open( my $infile, "<", $filename ) or die "could not open $filename: $!";
open( my $vef_output, ">","$filename.vef" )
    or die "could not open $filename.vef: $!";
open( my $svf_output, ">","$filename.svf" )
    or die "could not open $filename.svf: $!";

my $active_out;

while ( my $line = <$infile> ) {
    if ( $line =~ /SOME_LIBRARY_OPTIONS/ ) {
        $active_out = $vef_output;
    }
    # depending on your regex this conditional can be nested or not...
    if ( $line =~ /-sv/ ) {
        $active_out =  $svf_output;
    }
    next unless defined $active_out;
    print $active_out $line;
}

close($vef_output);
close($svf_output);
close($infile);

Код можно было бы написать в более простой и удобочитаемой форме.

      #!/usr/bin/env perl
#
# vim: ai ts=4 sw=4

use strict;
use warnings;

my $fh = shift
    or die "No file passed as argument for splitting!\n";

open my $in,          '<', $fh or die $!;
open my $out_match,   '>', $fh . 'vef' or die $!;
open my $out_nomatch, '>', $fh . 'svf' or die $!;

my $output_ready;
my $fh_out;

while ( <$in> ) {
        $output_ready = 1 if /SOME_LIBRARY_OPTIONS/;
        if( /-sv/ ) {
            $fh_out = $out_match;
        } else {
            $fh_out = $out_nomatch;
        }
        print $fh_out, $_ if $output_ready;
}

close $in;
close $out_match;
close $out_nomatch;
Другие вопросы по тегам