Как Perl может проверить, что путь является каталогом, но не может вызывать opendir () на том же самом? - PullRequest
3 голосов
/ 09 апреля 2019

Я пытаюсь найти пустые подкаталоги и удалить их.Я уверен, что есть лучшие способы добиться этого (я плохой программист и относительно новичок в Perl), но даже в этом случае я хотел бы понять, что не так с моим подходом.

use strict;
use warnings;
use File::Basename; 
use File::Find

my $lambda2 = sub
{
    my $path = $File::Find::name;
    if ( -d $path )
    {
        print("Directory: ", $path, "\n");

        # Define anonymous function to test if directory is empty
        my $hasContent = sub
        {
            my $directory = shift;
            opendir ( my $dh, $directory );
            return scalar ( grep { $_ ne "." && $_ ne ".." } readdir ( $dh ) );
        };
        # Remove item if it is an empty directory
        if ( ! $hasContent->( $path ) )
        {
            rmdir( $path );
        }
    }
};
my $directory = "/Users/username/testdir/";

find( { wanted => $lambda2, no_chdir => 1 }, $directory );

ЕслиУ testdir есть пустой подкаталог с именем testsubdir, скажем, я получаю, казалось бы, противоречивый ответ:

Directory: /Users/username/testdir
Directory: /Users/username/testdir/testsubdir
Can't opendir(/Users/username/testdir/testsubdir): No such file or directory

Печать последнего каталога подразумевает, что он прошел проверку -d, но в следующем сообщении об ошибке говорится, что неттакой каталог.Насколько я вижу, между ними ничего не происходит.

Ответы [ 3 ]

6 голосов
/ 09 апреля 2019

Код удаляет каталоги, так сказать, под ногами find.

Самое простое исправление: измените find на finddepth, для обход по порядку , так как

вызывает функцию &wanted для каталога после , вызывая его для содержимого каталога.

(оригинальный акцент) Тогда он не будет пытаться вызвать wanted для только что удаленного каталога.

Илипросто соберите список пустых каталогов в find и удалите их после завершения find.

4 голосов
/ 09 апреля 2019

Давайте добавим несколько операторов регистрации и посмотрим, что происходит:

my $lambda2 = sub {
    my $path = $File::Find::name;
    if ( -d $path ) {
        print("Directory: ", $path, "\n");
        my $hasContent = sub {
            my $directory = shift;
            opendir ( my $dh, $directory );
            return scalar ( grep { $_ ne "." && $_ ne ".." } readdir ( $dh ) );
        };
        my $hc = $hasContent->($path);
        print STDERR "hc($path) = $hc\n";
        if (! $hc) {
            print STDERR "Deleting $path\n";
            rmdir( $path );
        }
    }
};

$ mkdir -p /Users/username/testdir/testsubdir
$ perl subdir.pl
Directory: /Users/username/testdir
hc(/Users/username/testdir) = 1
Directory: /Users/username/testdir/testsubdir
hc(/Users/username/testdir/testsubdir) = 0
Deleting /Users/username/testdir/testsubdir
Can't opendir(/Users/username/testdir/testsubdir): No such file or directory
 at subdir.pl line 26.

Так что код более или менее работает, как задумано, просто File::Find пытается пройти /Users/username/testdir/testsubdir после того, как вы удалили его.

0 голосов
/ 09 апреля 2019

Использование du и awk.

Список всех пустых каталогов в $target_directory

 du $target_directory| awk '$1=="0"{print $2}'

Удаление всех пустых каталогов в $target_directory

 du $target_directory| awk '$1=="0"{system("rmdir "$2);}'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...