如何使用 Perl 删除目录及其空祖先?
How to remove a directory and its empty ancestors with Perl?
什么是Perl删除目录然后全部emptyparent 目录到第一个 non-empty 一个?换句话说,可以用什么来代替:
system 'rmdir', '-p', $directory;
,从 d
开始,将首先删除 d
,然后删除 c
,然后删除 b
,但不会删除 a
,因为 a
仍然包含 x
,像这样:
a
a/b
a/b/c
a/b/c/d
a/x
导致
a
a/x
它不是 built-in rmdir
,因为它只能删除一个 单个 目录。 (doc)
它不是 finddepth ( sub {rmdir}, '.' )
,使用 File::Find
,因为它删除了 children,而不是 parent。 (doc)
它也不是 File::Path
模块的 remove_tree
功能,因为它不仅会删除 children 目录,还会删除 文件 。 (doc)
注意,remove_tree
和finddepth
的工作方向与Bash相反rmdir --parent
。
一如既往,用我最喜欢的Path::Tiny
use 5.014;
use warnings;
use Path::Tiny;
use autodie;
my $p = path('a/b/c/d'); # starting
die "$p is not a dir" unless -d $p;
while( ! $p->children ) { # if it is empty
rmdir $p; # remove it
$p = $p->parent; # go upward
}
据我所知这不存在。您可以使用 Path::Tiny 相当轻松地自己编写它。这是一个简单的递归函数。
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
use Carp;
use Path::Tiny;
use autodie;
sub Path::Tiny::rmdir_if_empty {
my $self = shift;
# Stop when we reach the parent.
# You can't rmdir('.') anyway.
return if $self eq '.';
croak "$self is not a directory" if !$self->is_dir;
# Stop if the directory contains anything.
# I use an iterator to avoid a possibly very long list.
my $iter = $self->iterator;
return if defined $iter->();
# rmdir will not delete a non-empty directory, a second safeguard
rmdir $self;
return $self->parent->rmdir_if_empty;
}
path("a/b/c/d")->rmdir_if_empty;
use Path::Tiny qw( path );
my $p = path('a/b/c/d');
while (!$p->is_rootdir()) {
if (!rmdir($p)) {
last if $!{ENOTEMPTY};
die("Can't remove \"$p\": $!\n");
}
$p = $p->parent;
}
备注:
高效。通过检查 rmdir
的结果而不是使用 ->children
或 ->iterator
,此解决方案避免了对 readdir
.
的不必要调用
没有竞争条件。与使用 readdir
的解决方案(通过 ->children
或 ->iterator
)不同,此解决方案不会出现竞争条件。
此解决方案还避免了早期解决方案使用的冗余 -d
检查。
与之前的解决方案不同,此解决方案将处理除要删除的目录外为空的树。
什么是Perl删除目录然后全部emptyparent 目录到第一个 non-empty 一个?换句话说,可以用什么来代替:
system 'rmdir', '-p', $directory;
,从 d
开始,将首先删除 d
,然后删除 c
,然后删除 b
,但不会删除 a
,因为 a
仍然包含 x
,像这样:
a
a/b
a/b/c
a/b/c/d
a/x
导致
a
a/x
它不是 built-in rmdir
,因为它只能删除一个 单个 目录。 (doc)
它不是 finddepth ( sub {rmdir}, '.' )
,使用 File::Find
,因为它删除了 children,而不是 parent。 (doc)
它也不是 File::Path
模块的 remove_tree
功能,因为它不仅会删除 children 目录,还会删除 文件 。 (doc)
注意,remove_tree
和finddepth
的工作方向与Bash相反rmdir --parent
。
一如既往,用我最喜欢的Path::Tiny
use 5.014;
use warnings;
use Path::Tiny;
use autodie;
my $p = path('a/b/c/d'); # starting
die "$p is not a dir" unless -d $p;
while( ! $p->children ) { # if it is empty
rmdir $p; # remove it
$p = $p->parent; # go upward
}
据我所知这不存在。您可以使用 Path::Tiny 相当轻松地自己编写它。这是一个简单的递归函数。
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
use Carp;
use Path::Tiny;
use autodie;
sub Path::Tiny::rmdir_if_empty {
my $self = shift;
# Stop when we reach the parent.
# You can't rmdir('.') anyway.
return if $self eq '.';
croak "$self is not a directory" if !$self->is_dir;
# Stop if the directory contains anything.
# I use an iterator to avoid a possibly very long list.
my $iter = $self->iterator;
return if defined $iter->();
# rmdir will not delete a non-empty directory, a second safeguard
rmdir $self;
return $self->parent->rmdir_if_empty;
}
path("a/b/c/d")->rmdir_if_empty;
use Path::Tiny qw( path );
my $p = path('a/b/c/d');
while (!$p->is_rootdir()) {
if (!rmdir($p)) {
last if $!{ENOTEMPTY};
die("Can't remove \"$p\": $!\n");
}
$p = $p->parent;
}
备注:
高效。通过检查
rmdir
的结果而不是使用->children
或->iterator
,此解决方案避免了对readdir
. 的不必要调用
没有竞争条件。与使用
readdir
的解决方案(通过->children
或->iterator
)不同,此解决方案不会出现竞争条件。此解决方案还避免了早期解决方案使用的冗余
-d
检查。与之前的解决方案不同,此解决方案将处理除要删除的目录外为空的树。