修改perl中的脚本

时间:2015-07-17 11:24:57

标签: perl

目前我有以下脚本

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

my %seen;

my $header = <> . <>;
print $header;

my $last_sequence_number = 0;

open( my $output, ">", "output.$last_sequence_number.out" ) or die $!;
print {$output} $header;
$seen{$last_sequence_number}++;

while (<>) {
    my ($key) = split;
    next unless $key =~ m/^\d+$/;
    my $sequence_number = int( $key / 1000 );
    if ( not $sequence_number == $last_sequence_number ) {
        print "Opening new file for $sequence_number\n";
        close($output);
        open( $output, ">", "output.$sequence_number.out" ) or die $!;
        print {$output} $header unless $seen{$sequence_number}++;
        $last_sequence_number = $sequence_number;
    }
    print {$output} $_;
}

脚本将文件拆分为带有模式文件1文件2的其他文件...现在我需要向脚本传递另一个参数,该参数允许为输出指定前缀,因此如果此附加输入为{{1那么输出就是

11_file1 ....等等......我怎么能这样做?

我知道像

这样的东西
1_file2

可以用吗?

尝试了这个

use Getopt::Long;

但这不起作用。有什么问题?

我得到了

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

my %seen;

my $header = <> . <>;
print $header;
my ( $suffix, $filename ) = @ARGV;
open ( my $input, "<", $filename ) or die $!;                                   
my $last_sequence_number = 0;

open( my $output, ">", "output.$last_sequence_number.out" ) or die $!;
print {$output} $header;
$seen{$last_sequence_number}++;

while (<$input>) {
    my ($key) = split;
    next unless $key =~ m/^\d+$/;
    my $sequence_number = int( $key / 1000 );
    if ( not $sequence_number == $last_sequence_number ) {
        print "Opening new file for $sequence_number\n";
        close($output);
        open( $output, ">", "output.$sequence_number.out" ) or die $!;
        print {$output} $header unless $seen{$sequence_number}++;
        $last_sequence_number = $sequence_number;
    }
    print {$output} $_;
}
打印标题后

3 个答案:

答案 0 :(得分:2)

正如Sobrique所说,你的问题是<>的神奇本质。但我认为这并不像他想的那样难以应对。

重点是<>查看@ARGV当前值。因此,只要您确保在首次使用@ARGV之前已将其从<>中删除,就可以添加其他命令行参数。

所以改变你的代码,使它像这样开始:

my %seen;

my $prefix = shift;

my $header = <> . <>;

然后你可以这样调用你的程序:

$ your_program.pl prefix_goes_here list of file names...

其他所有内容现在应该与目前相同,但您的前缀存储在$prefix中,以便您可以在print语句中使用它。

我希望这就是你想要的。你的问题不是特别清楚。

答案 1 :(得分:1)

我会做这样的事情。

#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Getopt::Long qw(:config bundling);
use Pod::Usage;

{
    my $man          = 0;
    my $help         = 0;
    my $verbose      = 0;
    my $prefix       = '';
    my $suffix       = '';
    my $header_lines = 2;
    my $bunch_size   = 1000;

    GetOptions(
        'help|?'                 => \$help,
        'man'                    => \$man,
        'verbose|v+'             => \$verbose,
        'prefix|p=s'             => \$prefix,
        'suffix|s=s'             => \$suffix,
        'header|h=i'             => \$header_lines,
        'bunch|batch|bucket|b=i' => \$bunch_size
    ) or pod2usage(2);
    pod2usage(1) if $help;
    pod2usage( -exitval => 0, -verbose => 2 ) if $man;
    pod2usage(
        -exitval => 3,
        -message => "Headers lines can't be negative number"
    ) if $header_lines < 0;
    pod2usage(
        -exitval => 4,
        -message => "Bunch size has to be positive"
    ) unless $bunch_size > 0;

    my $header = '';
    $header .= <> for 1 .. $header_lines;

    my %seen;
    my $current_output_number = -1;

    sub key2output { int( shift() / $bunch_size ) }

    sub set_output {
        my $output_number = shift;
        if ( $output_number != $current_output_number ) {
            my $seen = $seen{$output_number}++;
            printf STDOUT "Opening %sfile for %d\n", $seen ? '' : 'new ',
                $output_number
                if $verbose;
            open my $fh, $seen ? '>>' : '>',
                $prefix . $output_number . $suffix;
            select $fh;
            print $header unless $seen;
            $current_output_number = $output_number;
        }
    }
}

while (<>) {
    my ($key) = /^(\d+)\s/;
    next unless defined $key;
    set_output( key2output($key) );
    print;
}

__END__

=head1 NAME

code.pl - splits file by first number by thousands

=head1 SYNOPSIS

code.pl [options] [file ...]

 Options:
   --help            brief help message
   --man             full documentation
   --prefix          output filename prefix
   --suffix          outpit filename suffix
   --header          number of header lines (default: 2)

=head1 OPTIONS

=over 8

=item B<--help>

Print a brief help message and exits.

=item B<--man>

Prints the manual page and exits.

=back

=head1 DESCRIPTION

B<This program> will read the given input file(s) and do something
useful with the contents thereof.

=cut

只需完成文档,您就可以将其发送给您的同事。

答案 2 :(得分:0)

你遇到的问题是钻石操作员<>是一种特殊的perl魔法。

'命令行上的所有文件名'打开它们并按顺序处理它们。

要做你想做的事情:

my ( $suffix, $filename ) = @ARGV;
open ( my $input, "<", $filename ) or die $!; 

然后您可以将while循环更改为:

while ( <$input> ) {

根据您的需要修改输出文件名。关键不同的是,它只需要一个文件名 - 第一个arg是后缀,第二个是名称。

您可以通过以下方式扩展它:

my ( $suffix, @names ) = @ARGV;

然后运行foreach循环:

foreach my $filename ( @names ) { 
    open .... #etc