如何使用 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_treefinddepth的工作方向与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 检查。

  • 与之前的解决方案不同,此解决方案将处理除要删除的目录外为空的树。