2013-02-12 2 views
-1

Я хочу написать скрипт Perl, который начинается в начале дерева каталогов (предоставляется в аргументах командной строки) и рекурсивно перемещается по каждому подкаталогу, выполняя определенное действие для каждого файл.Perl-скрипт, который повторяется через дерево каталогов

Для этого я использую finddepth, однако он не работает, когда я запускаю сценарий в каталоге, который находится на двух уровнях или более из базового каталога.

Вот мой код:

#!/usr/local/bin/perl -w 

use strict; 

use File::Copy; 
use File::Find; 
use File::Basename; 
use File::Path; 

finddepth(\&file_list, @ARGV); 

sub file_list { 

    my ($file_path, $name, $path, $suffix); 

    $file_path = $File::Find::name; 

    ($name, $path, $suffix) = fileparse($file_path, /\.*/); 

    my $fullname = $name . $suffix; 
    my $file = $fullname; 

    if ($file =~ /^[^\.].*[^\.pl]$/) { 

     copy($file, "$file.orig"); 

     open(FILE, "$file"); 
     my @file_data = <FILE>; 
     close(FILE); 

     open(FOUT, ">$file") or die " \n File cannot be opened !"; 

     foreach my $line (@file_data) { 
      if ($line =~ /^\s+Error:/) { 
       $line =~ s/([^-]\d+)/ \*\*/gc; 
       print FOUT $line; 
      } 
      else { 
       print FOUT $line; 
      } 
     } 
     close(FOUT); 
    } 
} 

Следующие предупреждения/ошибка последовательно брошены:

  1. Читать на закрытом дескрипторе
  2. Файл не может быть открыт!

Я не могу понять, почему это происходит. Я постарался сделать свой вопрос максимально конкретным. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация. Спасибо.

+1

Вы используете 'strict', но почему бы не« предупреждения »? –

+2

Куда уходят эти предупреждения/ошибки? Разве они не показывают имя файла? Номер строки? –

+0

Каково ваше регулярное выражение '/^[^ \.]. * [^ \. Pl] $ /' должно совпадать? – Borodin

ответ

1

Вы не можете открыть файл, потому что $file оказывается каталогом в этот момент времени, поэтому вам нужно добавить чек для этого.

Возможно, стоит добавить инструкцию or die при открытии файла для чтения.

Также обратите внимание, что File::Find устанавливает $_ в имя текущего файла, поэтому 5 строк, которые вы берете для производства $file, на самом деле не нужны.

+0

Ну, это то, что я тоже думал. Но затем я перешел на страницу perldocs для File :: Find (http://perldoc.perl.org/File/Find.html), и я понял, что find() автоматически выполняет chdir() для каждого каталога и затем возобновляет поиск файлов оттуда. Поскольку finddepth в основном то же самое, что и find, он должен идеально работать. – pandabear

+0

Точка о 'chdir()' правильная. Именно по этой причине вы можете просто открывать имя файла и не нуждаться в полном пути. – stevenl

+0

В таком случае, не следует ли perl заботиться об этой проблеме? И я открываю имя файла, то есть $ fullname = $ name. $ Suffix, а не путь к файлу. – pandabear

1

Есть несколько проблем с кодом.

  • use warnings предпочтительнее командной строки -w

  • Объявите переменные в их первом месте использования, а не в блоке в верхней части подпрограммы

  • Используйте три -параметр формы open и лексические файловые дескрипторы

  • При проверке состояния вызова open поместите встроенную переменную $! в die строке, так что вы знаете, почему открытое не удалось

  • Не помещайте скалярные переменные в двойных кавычках. Это, вероятно, не нужно, и при некоторых обстоятельствах может нарушить ваш код. Крайне маловероятно, чтобы сделать все, что вы хотите

Это переписывание вашей программы использует use autodie, чтобы избежать необходимости явных open ... or die $! заявлений. Он использует rename, чтобы изменить имя файла, а не копировать его и перезаписать оригинал.

Вместо того, чтобы читать весь файл в память, открыть переименованный файл и читать построчно, редактирования и записи каждой строки в новый файл

я написал его так, что он игнорирует файлы, начинающиеся с точка или конец с .pl - Я надеюсь, что это правильно. Я также очень сомневаюсь в вашей замене s/[^-]\d+/ **/g, которая ищет последовательность цифр, которым предшествует символ, который не является дефисом; это правильно?

#!/usr/local/bin/perl 

use strict; 
use warnings; 

use autodie; 
no autodie 'unlink'; 

use File::Find 'finddepth'; 

finddepth(\&file_list, @ARGV); 

sub file_list { 

    return unless -f; 
    return if /^\./ or /\.pl$/; 

    my $file = $_; 
    my $orig = "$file.orig"; 

    unlink $orig; 
    rename $file, $orig; 

    open my $infh, '<', $orig; 
    open my $outfh, '>', $file; 

    while (my $line = <$infh>) { 
    if ($line =~ /^\s+Error:/) { 
     $line =~ s/[^-]\d+/ **/g 
    } 
    print $outfh $line; 
    } 

    close $outfh; 
} 
+0

Мне не было известно об испытании файла -f. После добавления теста -f мой код работает нормально. Спасибо. – pandabear

+0

Рад помочь. Надеюсь, вы обратили внимание на мои другие вопросы, поскольку они - практики, которые помогут вам написать хороший, надежный код. – Borodin

+0

Да, у меня есть. Что касается моей подстановки, я стараюсь избегать замены отрицательных чисел. Почему вы думаете, что это сомнительно? Я только начинаю с perl, поэтому я все еще немного борюсь с регулярными выражениями. – pandabear

Смежные вопросы