在多个文件中使用Schwartzian变换

时间:2016-09-19 08:20:21

标签: perl sorting

我想在文件夹中的多个文件中使用以下Schwartzian变换排序脚本(完全作为独立脚本工作):

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

open my $input, '<', '/home/test/file1' or die "Unable to open input file: $!";
my @file = <$input>;
my @sorted_file = map { $_->[0] }
             sort { $a->[1] <=> $b->[1] }
             map { my ($x) = $_ =~ /VerNumber:\((\d+)/i; [$_, $x]; }
             @file;
open my $output, '>', '/home/test/sorted/file1' or die "Unable to open output file: $!";
print $output $_ for @sorted_file;

脚本应该将一个文件夹中的所有文件作为输入,以文件*开头,并对每个文件的内容进行排序:

file1.txt
file2.txt
...
file1000.txt

然后,作为输出,我希望脚本创建新文件夹,在其中放置新文件,并使用已排序的内容保留相同的文件名。

/sorted
file1.txt -> /sorted/file1.txt
file2.txt -> /sorted/file2.txt
...
file1000.txt -> /sorted/file1000.txt

有什么想法可以如何做到这一点?我有近1000个文件,每个文件包含大约3000个数组,这些数据按照上述脚本进行排序。

我做了一个尝试。以下脚本会将文件写入输出文件夹,保留相同的文件名,但排序部分不起作用(即使独立脚本正在对文件进行排序)。我在输出中获得了相同的文件。

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;

my $version="0.2";
my $files_match="";
my $files_dir="";
my $file_name="";
my $help_flag="";
my $version_flag="";

GetOptions(
           'm|match=s' => \$files_match,
           'd|directory=s' => \$files_dir,
           'h|help' => \$help_flag, 'v|version' => \$version_flag,
);

sub sorting {
my @file = "$_";
my @sorted = map { $_->[0] }
             sort { $a->[1] <=> $b->[1] }
             map { my ($x) = $_ =~ /VerNumber:\((\d+)/i; [$_, $x]; }
             @file;
print FILE $_;
}

if (($files_match ne "") and ($files_dir ne "")) {
        chdir("$files_dir") or die "$!";
        opendir (DIR, ".") or die "$!";
        my @files = grep {/$files_match/} readdir DIR;
        my $files_size = $#files + 1;
        my $index_file = 1;
        print "Files to process: $files_size\n";
        close DIR;

        foreach (@files) {
                open(FILE, ">./sorted/$_.sort") or die $!;
                my @singlefile = $_;
                print "Processing $index_file of $files_size files: $_\n";
                local @ARGV = @singlefile;
                while(<>){
                       sorting($_);
                }    
                close(FILE);
                $index_file++;
                print "OK: Sorted @singlefile \n";
        }
    } elsif ((!$help_flag) and (!$version_flag)){printHelp();}

我是Perl的初学者,任何帮助都会受到欢迎!

提前谢谢!

1 个答案:

答案 0 :(得分:1)

您有代码来排序一个文件。将该代码放入子例程中。称之为sort_one_file()

sub sort_one_file {
  # You have this code already
}

虽然这不太对劲。您需要定义$input$output变量。我们假设我们要将它们传递给子程序。

sub sort_one_file {
  my ($input, $output) = @_;

  # You already have this code
}

确定。那我们怎么称呼这个功能呢。这很容易。

sort_one_file($input, $output);

您没有向我们展示在原始程序中填充$input$output的代码,但如果您将其添加回来,那么这将与您当前程序的工作方式相同。

但现在我们要多次调用我们的子程序。让我们自己轻松一下,并假设我们将输入文件列表作为命令行参数传递给我们的程序。这使我们的计划尽可能灵活。

foreach my $input (@ARGV) {
  sort_one_file($input, $output);
}

我们差不多了,但我们有一个小问题。我们可以从$input获得@ARGV,但$output呢?好吧,我不知道你用来重命名文件的规则。所以让我们做一些假设并将它们隐藏在另一个子程序中。

sub get_output_name {
  my ($input) = @_;

  # Change this to whatever renaming rule you are using.
  return "$input.new";
}

然后我们可以在循环中使用它。

foreach my $input (@ARGV) {
  sort_one_file($input, get_output_name($input));
}

还有其他方法。我可能只是使用<>,这样我就不需要打开输入文件了(然后我需要跟踪$ARGV中的内容,以便知道我什么时候开始处理一个新文件)。但这很简单,也可以。

更新:正如其他人在评论中指出的那样,您打开文件的现有代码不正确。你有:

open my $input, '<' or die "Unable to open input file: $!";

这不包括要打开的文件的名称。我想你想要这个:

open my $input_fh, '<', $input
  or die "Unable to open input file: $input - $!";

您还需要将下一行更改为:

my @file = <$input_fh>;

输出open()存在同样的问题。

但实际上,@file数组完全没必要。我写的是:

open my $input_fh,  '<', $input
  or die "Unable to open input file: $input - $!";
open my $output_fh, '>', $output
  or die "Unable to open output file: $output - $!";

print $output_fh map { $_->[0] }
                 sort { $a->[1] <=> $b->[1] }
                 map { my ($x) = $_ =~ /VerNumber:\((\d+)/i; [$_, $x]; }
                 <$input_fh>;