문제

I am trying to write a perl script which checks all the directories in the current directory and then accordingly penetrates in the subsequent directories to the point where it contains the last directory. This is what I have written:

#!/usr/bin/perl -w
use strict;
my @files = <*>;
foreach my $file (@files){
    if (-d $file){
            my $cmd = qx |chown deep:deep $file|;
            my $chdir = qx |cd $file|;
            my @subfiles = <*>:
            foreach my $ subfile(@subfiles){
                if (-d $file){
                    my $cmd = qx |chown deep:deep $subfile|;
                    my $chdir = qx |cd $subfile|;
            .  # So, on in subdirectories
            .
            .
            }
    }

    }
 }

Now, some of the directories I have conatins around 50 sub directories. How can I penetrate through it without writing 50 if conditions? Please suggest. Thank you.

도움이 되었습니까?

해결책 3

NOTE: The OS usually won't let you change ownership of a file or directory unless you are the superuser (i.e. root).

Now, we got that out of the way...

The File::Find module does what you want. Use use warnings; instead of -w:

use strict;
use warnings;
use feature qw(say);
use autodie;
use File::Find;

finddepth sub {
    return unless -d;    #  You want only directories...
    chown deep, deep, $File::Find::name
        or warn qq(Couldn't change ownership of "$File::Find::name\n");
}, ".";

The File::Find package imports a find and a finddepth subroutine into your Perl program.

Both work pretty much the same. They both recurse deeply into your directory and both take as their first argument a subroutine that's used to operate on the found files, and list of directories to operate on.

The name of the file is placed in $_ and you are placed in the directory of that file. That makes it easy to run the standard tests on the file. Here, I'm rejecting anything that's not a directory. It's one of the few places where I'll use $_ as the default.

The full name of the file (from the directory you're searching is placed in $File::Find::name and the name of that file's directory is $File::Find::dir.

I prefer to put my subroutine embedded in my find, but you can also put a reference to another subroutine in there too. Both of these are more or less equivalent:

my @directories;
find sub {
   return unless -d;
   push @directories, $File::Find::name;
}, ".";


my @directories;
find \&wanted, ".";

sub wanted {
   return unless -d;
   push @directories, $File::Find::name;
}

In both of these, I'm gathering the names of all of the directories in my path and putting them in @directories. I like the first one because it keeps my wanted subroutine and my find together. Plus, the mysteriously undeclared @directories in my subroutine doesn't look so mysterious and undeclared. I declared my @directories; right above the find.

By the way, this is how I usually use find. I find what I want, and place them into an array. Otherwise, you're stuck putting all of your code into your wanted subroutine.

다른 팁

Well, a CS101 way (if this is just an exercise) is to use a recursive function

sub dir_perms {
 $path = shift;
  opendir(DIR, $path);
  my @files = grep { !/^\.{1,2}$/ } readdir(DIR); # ignore ./. and ./..
  closedir(DIR);
  for (@files) {
   if ( -d $_ ) {
    dir_perms($_);
  }
  else {
   my $cmd = qx |chown deep:deep $_|;
   system($cmd);
  }
 }
}

dir_perms(".");

But I'd also look at File::Find for something more elegant and robust (this can get caught in a circular link trap, and errors out if you don't call it on a directory, etc.), and for that matter I'd look at plain old UNIX find(1), which can do exactly what you're trying to do with the -exec option, eg

/bin/bash$ find /path/to/wherever -type f -exec chown deep:deep {} \;

perldoc File::Find has examples for what you are doing. Eg,

       use File::Find;
       finddepth(\&wanted, @directories_to_search);
       sub wanted { ... }

further down the doc, it says you can use find2perl to create the wanted{} subproc.

 find2perl / -name .nfs\* -mtime +7 \
           -exec rm -f {} \; -o -fstype nfs -prune
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top