2016-09-19 38 views
-1

我想用下面的Schwartzian轉換排序腳本(這是工作完全作爲一個獨立的腳本),在多個文件夾中的變換:使用的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的初學者,任何幫助都會比歡迎!

預先感謝您!

+3

如果您已經嘗試編寫解決方案但無法使其工作,我們將很樂意幫助您。如果你不嘗試某些東西*,你將永遠留在初學者。 – Borodin

+1

Your line'打開我的$輸出,'>'或死「無法打開輸出文件:$!」'是錯誤的。你還沒有提供文件名。 – Borodin

+1

「open my $ input」,「<」或「...」 - 缺少文件名。使用核心模塊['File :: Path'](http://perldoc.perl.org/File/Path.html)中的'make_path'創建一個目錄。獲取要處理的文件列表,例如['glob'](http://perldoc.perl.org/functions/glob.html)。然後遍歷這個列表,主要是你在做什麼。讓我們知道是否有問題。 – zdim

回答

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); 
} 

我們快到了,但是我們有一個小問題。我們可以從@ARGV得到$input,但$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>;