0

首先,我无法使用 File::Find。

所以我有我的脚本来遍历目录并找到某种类型的文件。但是,如果我深入一个以上的子目录,我的脚本就不会一直正确退出到起始目录。我想我需要有一个 $previousDir 变量来跟踪最后一个目录,这样当我在子目录中完成时我可以说回到那个目录。但我试过把它放在多个地方都没有成功......

文件结构(粗体是目录,斜体是文件):

起始目录/日志 - AAADir1zzzadstatlog.299、adstatlog.tgz、文件

/ AAA -文件文件

/目录1 - /目录2 ,config.tar.gz

/目录2 - 空

/ zzz -内兹兹

这是我当前的脚本:

# specify the directory where you want to start the search
my $startingDir = $ARGV[0];
my $directoryCount = 0;
my $directory = shift;
my $previousDir;
my @directories;
my $tarOutput;

# Calling the Subroutine, which searches the Directory
readDirectory($startingDir);

sub readDirectory
{
    # Open and close the startingDir
    opendir(DIR, @_[0]) or die("ERROR: Couldn't open specified directory $!");
    my @files = grep { $_ !~ /^\.{1,2}$/ } readdir DIR;
    closedir DIR;

    print "------------------------------------------------------------------------\n\n";

    foreach my $currentFile (@files)
    {   
        print "Current File: ", $currentFile, "\n\n";

        #Directory currently searching through
        print "Searching in $directory\n\n";

        my $fullPath = "$directory/$currentFile";
        print "FULL PATH: $fullPath\n\n";
        if ( -d $fullPath )
        {
            print "Found New Directory: ", $currentFile, "\n\n";
            push (@directories, $currentFile);
            $directoryCount++;
            print "Current number = $directoryCount\n\n";
            print "Directories: @directories \n\n";
            $previousDir = $directory;
            $directory = $fullPath;
            # The Subroutine is calling hisself with the new parameters
            readDirectory($directory);
        }

        elsif ( $currentFile =~ /\.tar.gz$/i || $currentFile =~ /\.tar$/i || $currentFile =~ /\.tgz$/i)
        {
            print "File: ", $currentFile, "\n\n";
            my $tarOutput = `tar -tvzf $currentFile`;
            print $tarOutput, "\n";
            $previousDir = $directory;
        }

        print "PREVIOUSDIR: $previousDir\n\n";

        print "-----------------------------------------------------------------------\n\n";

        $directory = $previousDir;
    }   
}

和输出:(向下滚动以查看问题开始的位置)

------------------------------------------------------------------------

Current File: AAA

Searching in /home/gackerma/Logs

FULL PATH: /home/gackerma/Logs/AAA

Found New Directory: AAA

Current number = 1

Directories: AAA

------------------------------------------------------------------------

Current File: filefile

Searching in /home/gackerma/Logs/AAA

FULL PATH: /home/gackerma/Logs/AAA/filefile

PREVIOUSDIR: /home/gackerma/Logs

 ------------------------------------------------------------------

 PREVIOUSDIR: /home/gackerma/Logs

 ------------------------------------------------------------------

Current File: Dir1

Searching in /home/gackerma/Logs

FULL PATH: /home/gackerma/Logs/Dir1

Found New Directory: Dir1

Current number = 2

Directories: AAA Dir1

------------------------------------------------------------------------

Current File: DIR2

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/DIR2

Found New Directory: DIR2

Current number = 3

Directories: AAA Dir1 DIR2

------------------------------------------------------------------------

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------

Current File: configs.tar.gz

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/configs.tar.gz

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------

PREVIOUSDIR: /home/gackerma/Logs/Dir1  ***THIS IS WHERE THE ISSUE STARTS - 
                                          PREVIOUSDIR SHOULD BE /Logs!!***

------------------------------------------------------------------

Current File: file

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/file

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------

Current File: adstatlog.299

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/adstatlog.299

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------

Current File: zzz

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/zzz

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------

Current File: adstatlog.tgz

Searching in /home/gackerma/Logs/Dir1

FULL PATH: /home/gackerma/Logs/Dir1/adstatlog.tgz

PREVIOUSDIR: /home/gackerma/Logs/Dir1

------------------------------------------------------------------
4

3 回答 3

1

I would really use File::Find if you can.

Here's a working, simplified version of your recursive try:

use warnings;
use strict;

die "Usage: $0 (abs path to dir) " if @ARGV != 1;

my $dir = shift @ARGV;

file_find($dir);

sub file_find {
    my $dir = shift;

    opendir my $dh, $dir or warn "$dir: $!";
    my @files = grep { $_ !~ /^\.{1,2}$/ } readdir $dh;
    closedir $dh;

    for my $file ( @files ) { 
        my $path = "$dir/$file";

        if( $path =~ /(\.tar\.gz|\.tar|\.tgz)$/ ) { 
            print "do tar for $path\n";
        }   
        file_find($path) if -d $path;
    }   
}
于 2013-05-21T14:32:34.450 回答
0

你的程序有很多问题。主要错误是您使用了太多全局变量并试图手动使它们与您当前正在处理的目录保持同步。

这是一个列表

  • 始终 use strict为您编写use warnings的每个程序

  • warnings会告诉你你应该写opendir(DIR, $_[0])而不是opendir(DIR, @_[0])

  • 您设置$directory$previousDir在目录中的每个条目之后。但是$previousDir只有在当前条目是另一个目录时才设置,所以在普通文件之后,即使它没有保存,也会恢复该值。

  • 您对是否应该读取由全局变量$directory或传递给子例程的参数指定的目录感到困惑。

到目前为止,最简单的方法是使用 subroutine 参数来指定当前目录而忘记全局变量。这是一个程序,它可以满足您的预期

use strict;
use warnings;

process_dir($ARGV[0]);

sub process_dir {

  my ($dir) = @_;

  opendir my $dh, $dir or die $!;
  my @entries = grep { not /^\.\.?$/ } readdir $dh;
  closedir $dh;

  for my $entry (@entries) {
    my $fullname = "$dir/$entry";
    if (-d $fullname) {
      process_dir($fullname);
    }
    elsif ($entry=~ /(?:\.tar|\.tgz|\.tar\.gz)$/i)
      print "File: ", $fullname, "\n\n";
      print `tar -tvzf $fullname`;
    }
  }
}
于 2013-05-21T14:42:00.030 回答
0

File::Find模块自 Perl 5.000 以来一直是标准的 Unix 模块。事实上,从 Perl 3.x 开始,它就是一个标准模块,甚至可能更早。事实上,我在我的 Mac 上安装了 Perl 5.12,我仍然看到旧find.pl文件位于其中一个@INC目录中。

回到 Perl 5 之前(或者甚至在 Perl 4 之前),你会这样做:

require "find.pl";

代替

use File::Find;

在您的系统上获取find命令(find.pl用于向后兼容)。这就是为什么我很难相信你File::Find的系统上没有。dir这就像说您的 Windows PC 上没有该命令。

运行命令perl -V。那是资本V。这将打印出@INC目录列表。看看您是否File只能在该列表中列出的那些目录中找到一个目录。在那个目录下应该是一个Find.pmPerl 模块。

这是在我的运行 Strawberry Perl 的 PC 上的样子:

@INC:
  C:/perl/perl/site/lib
  C:/perl/perl/vendor/lib
  C:/perl/perl/lib
  . 

在我的 Mac 上,该@INC列表中列出了 10 个目录。

还可以查看您系统上的 Perl 版本。并且,确保@INC您可以读取其中列出的目录。

如果您的系统上没有 Perl,那么您的 Perl 安装肯定有问题File::FindFile::Find我会比它本身更担心这个。

还有一件事,看看你是否perldoc安装了命令。如果这样做,请键入:

$ perldoc File::Find

看看这是否为您提供了有关 File::Find 的任何文档。如果是,则意味着 File::Find 在您的系统上。然后运行:

$ perldoc -l File::Find

这将为您提供 File::Find 模块的位置。

在执行任何其他操作之前,请验证 File::Find 是否真的存在于您的系统中,或者您在执行其他操作之前没有对其的读取权限。正如我之前所说,如果您的系统上不存在这个模块,那么您的 Perl 安装就会出现重大问题,我会担心它是否可以信任。这需要解决。

如果一切正常,那么我们需要查看您的程序以找出您不能使用File::Find. 它可能是次要的,例如在程序名称周围使用引号。

于 2013-05-21T14:12:52.267 回答