打印行后跟匹配模式的行,到文件 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);

解决方法

虽然您的代码逻辑是正确的,并且您肯定会自己发现一些剩余的错别字,但我想建议对您的 while 循环进行修改:
输入文件的每一行都必须打印一次(可能除了输入文件的开头)。我宁愿切换输出文件句柄,而不是设置 $mode 标志并测试它,这会导致更清晰的代码:

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