通过目录树递归的Perl脚本

时间:2013-02-12 05:18:55

标签: perl recursion directory

我想编写一个从目录树顶部开始的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. 无法打开文件!
  3. 我似乎无法弄清楚为什么会这样。我试图让我的问题尽可能具体。如果您需要更多信息,请与我们联系。谢谢。

2 个答案:

答案 0 :(得分:1)

您无法打开该文件,因为$file恰好是该时间点的目录,因此您需要为此添加检查。

打开文件进行阅读时,可能需要添加or die语句。

另请注意,File::Find$_设置为当前文件名,因此您生成$file所用的5行实际上是不必要的。

答案 1 :(得分: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;
}