如何在给定路径中找到没有其他子文件夹的所有文件夹?它们可能包含文件,但没有其他文件夹。
例如,给定以下目录结构:
time/aa/
time/aa/bb
time/aa/bb/something/*
time/aa/bc
time/aa/bc/anything/*
time/aa/bc/everything/*
time/ab/
time/ab/cc
time/ab/cc/here/*
time/ab/cc/there/*
time/ab/cd
time/ab/cd/everywhere/*
time/ac/
find(time)
的输出应如下:
time/aa/bb/something/*
time/aa/bc/anything/*
time/aa/bc/everything/*
time/ab/cc/here/*
time/ab/cc/there/*
time/ab/cd/everywhere/*
上面的 *
表示文件。
答案 0 :(得分:8)
您想要编写目录漫游者的任何时间,始终使用标准File::Find模块。在处理文件系统时,你必须能够处理奇怪的角落情况,并且天真的实现很少。
environment provided to the callback(文档中名为wanted
)有三个变量,对您想要做的事情特别有用。
$File::Find::dir
是当前目录名称
$_
是该目录中的当前文件名
$File::Find::name
是文件的完整路径名
当我们找到一个不是.
或..
的目录时,我们会记录完整路径并删除它的父目录,我们现在知道它不能是叶子目录。最后,由于find
in File::Find执行depth-first search,因此保留的所有记录路径必须为离开。
#! /usr/bin/env perl
use strict;
use warnings;
use File::Find;
@ARGV = (".") unless @ARGV;
my %dirs;
sub wanted {
return unless -d && !/^\.\.?\z/;
++$dirs{$File::Find::name};
delete $dirs{$File::Find::dir};
}
find \&wanted, @ARGV;
print "$_\n" for sort keys %dirs;
您可以针对当前目录的子目录
运行它$ leaf-dirs time time/aa/bb/something time/aa/bc/anything time/aa/bc/everything time/ab/cc/here time/ab/cc/there time/ab/cd/everywhere
或使用完整路径
$ leaf-dirs /tmp/time /tmp/time/aa/bb/something /tmp/time/aa/bc/anything /tmp/time/aa/bc/everything /tmp/time/ab/cc/here /tmp/time/ab/cc/there /tmp/time/ab/cd/everywhere
或在同一个调用中检测多个目录。
$ mkdir -p /tmp/foo/bar/baz/quux $ leaf-dirs /tmp/time /tmp/foo /tmp/foo/bar/baz/quux /tmp/time/aa/bb/something /tmp/time/aa/bc/anything /tmp/time/aa/bc/everything /tmp/time/ab/cc/here /tmp/time/ab/cc/there /tmp/time/ab/cd/everywhere
答案 1 :(得分:1)
基本上,您打开根文件夹并使用以下过程:
sub child_dirs {
my ($directory) = @_;
打开目录
opendir my $dir, $directory or die $!;
选择 文件此目录中的文件其中文件是目录
my @subdirs = grep {-d $_ and not m</\.\.?$>} map "$directory/$_", readdir $dir;
# ^-- directory and not . or .. ^-- use full name
如果,此类所选文件的列表包含元素,
3.1。 然后递归到每个这样的目录,
3.2。 else 此目录是“leaf”,它将附加到输出文件。
if (@subdirs) {
return map {child_dirs($_)} @subdirs;
} else {
return "$directory/*";
}
# OR: @subdirs ? map {child_dirs($_)} @subdirs : "$directory/*";
}
使用示例:
say $_ for child_dirs("time"); # dir `time' has to be in current directory.
答案 2 :(得分:0)
这个功能可以做到。只需用您的初始路径调用它:
sub isChild {
my $folder = shift;
my $isChild = 1;
opendir(my $dh, $folder) || die "can't opendir $folder: $!";
while (readdir($dh)) {
next if (/^\.{1,2}$/); # skip . and ..
if (-d "$folder/$_") {
$isChild = 0;
isChild("$folder/$_");
}
}
closedir $dh;
if ($isChild) { print "$folder\n"; }
}
答案 3 :(得分:0)
我尝试了readdir做事的方式。然后我偶然发现了......
use File::Find::Rule;
# find all the subdirectories of a given directory
my @subdirs = File::Find::Rule->directory->in( $directory );
我从此输出中删除了与字符串的初始部分匹配且没有一些叶条目的任何条目。