有谁知道如何在数千个子目录中搜索所有仅包含 1 个文件且不超过 1 个文件的目录?
关于使用什么工具或简单的代码片段有什么建议吗?
答案1
在 PowerShell 中,你可以这样做:
PS> Get-ChildItem -recurse | `
Where {$_.PSIsContainer -and `
@(Get-ChildItem $_.Fullname | Where {!$_.PSIsContainer}).Length -eq 1}
$_.PSIsContainer
对于目录,返回 true;对于文件,返回 false。该语法@()
确保表达式的结果是一个数组。如果其长度为 1,则该目录中只有一个文件。此示例还使用了嵌套管道,例如Get-ChildItem $_.Fullname | Where {...}
在第一个 Where 脚本块中。
答案2
如果这是在 Linux 上,我会倾向于使用这样的命令。
find . -type 'f' -printf '%h\n' | sort | uniq -c
find 命令将打印出所有文件的目录名称。然后我们对其进行排序,然后使用 uniq 的 -c 选项来获得每个目录的文件数量。一旦您知道每个目录的数量,就应该很容易 grep 出值为 1 的目录。
如果您希望对目录执行操作并将其保持在一行中,则可以通过 awk 将结果传送到 xargs。例如,要删除每个文件夹:
find . -type 'f' -printf '%h\n' | sort | uniq -c | awk '{ if ($1 == "1") printf "%s%c",$2,0 }' | xargs -0 -I {} rm -rf {}
这会将每个值为 1 的目录打印到以空字符结尾的字符串中,然后可以将其作为 xargs 的参数。使用以空字符结尾的字符串,这样空格就会按预期处理。在 xargs 中,{} 字符将被每个传递的参数替换。
答案3
这是一个 Perl 解决方案(在 Windows 上测试):
#!perl
use strict;
use warnings;
use File::Find;
use File::Slurp;
use File::Spec::Functions qw(catfile canonpath rel2abs);
my ($top) = @ARGV;
die "Provide top directory\n" unless defined($top) and length $top;
find(\&wanted, $top);
sub wanted {
my $name = $File::Find::name;
return unless -d $name;
return unless 1 == grep { -f catfile($name, $_) } read_dir $name;
print canonpath(rel2abs $name), "\n";
}
输出:
C:\Temp> f 。 目录:\Temp\1 目录:\Temp\chrome_9999 目录:\Temp\CR_3E.tmp
答案4
解决方案:
sub wanted {
my $name = $File::Find::name;
return unless -d $name;
return unless 1 == grep { -f catfile($name, $_) } read_dir $name;
print canonpath(rel2abs $name), "\n";
}
不必要地读取每个目录来计算其中的项目,然后在实际下降时再次读取它(作为框架的一部分File::Find
)。
一个更简单的解决方案就是下降,将每个文件的存在记录到包含它的目录中:
my %count = 0;
...
sub wanted {
return unless -f;
$count{$File::Find::dir}++;
}
my @one_file_dirs = sort grep { $count{$_} == 1 } keys %count;