Perl Directory Walking issue - Can't go back up more than 1 directory properly

放肆的年华 提交于 2019-12-12 02:55:59

问题


First off, I don't have the ability to use File::Find.

So I have my script to walk through directories and find a certain type of file. But if I go more than one sub-directory deep, my script doesn't properly exit all the way back up to the starting directory. I think I need to have a $previousDir variable that keeps track of the last directory so I can say to go back out to that one when I'm done in the sub-directory. But I've tried putting it in multiple places without success...

File Structure (BOLD is a Dir, Italic is a file):

startingdirectory/Logs - AAA, Dir1, zzz, adstatlog.299, adstatlog.tgz, file

/AAA - filefile

/Dir1 - /Dir2, config.tar.gz

/Dir2 - EMPTY

/zzz - withinzzz

Here is my current script:

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

And the output: (scroll down to see where issue begins)

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

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

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

回答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;
    }   
}



回答2:


The File::Find module has been a standard Unix module since Perl 5.000. In fact, it's been a standard module since Perl 3.x, maybe even before. In fact, I have Perl 5.12 installed on my Mac, and I still see the old find.pl file sitting in one of the @INC directories.

Back before Perl 5 (or maybe even before Perl 4), you'd do this:

require "find.pl";

instead of

use File::Find;

TO get the find command on your system (find.pl is there for backwards compatibility). This is why I find it so hard to believe you don't have File::Find on your system. It'd be like saying you don't have the dir command on your Windows PC.

Run the command perl -V. That's a capital V. This will print out the @INC directory list. See if you can find a File directory in only of those directories listed in that list. Under that directory should be a Find.pm Perl module.

Here's what it looks like on my PC running Strawberry Perl:

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

On my Mac, 10 directories are listed in that @INC list.

Also see which version of Perl you have on your system. And, make sure the directories listed in @INC are readable by you.

There is something definitely wrong with your Perl installation if you don't have File::Find on your system. I'd be more worried about that than File::Find itself.

One more thing, see if you have perldoc command installed. If you do, type:

$ perldoc File::Find

and see if that gives you any documentation on File::Find. If it does, it means that File::Find is on your system. Then run:

$ perldoc -l File::Find

which will give you the location of the File::Find module.

Before doing anything else, verify that File::Find really, really doesn't exist on your system, or that you don't have read access to it before doing anything else. As I said before, if this module doesn't exist on your system, you have major problems with your Perl installation, and I'd be worried whether it can be trusted. This needs to be resolved.

If everything is okay, then we need to see your program to figure out why you can't use File::Find. It might be something minor, like using quotes around the program's name.




回答3:


There are a number of problems with your program. The main error is that you are using too many global variables and trying to manually keep them in synch with the directory you are currently processing.

Here is a list

  • Always use strict and use warnings for every program you write

  • warnings would have told you that you should write opendir(DIR, $_[0]) instead of opendir(DIR, @_[0])

  • You are setting $directory to $previousDir after every entry in a directory. But $previousDir is being set only when the current entry is another directory, so after ordinary files the value is restored even though it hasn't been saved.

  • You are getting confused about whether you should be reading the directory specified by global variable $directory or by the parameter passed to the subroutine.

By far the easiest way to do this is to use only the subroutine parameter to specify the current directory and forget about the global variable. Here is a program that does what yours is intended to

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


来源:https://stackoverflow.com/questions/16671127/perl-directory-walking-issue-cant-go-back-up-more-than-1-directory-properly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!