djangofan Asked: 2009-10-15 10:24:21 +0800 CST2009-10-15 10:24:21 +0800 CST 2009-10-15 10:24:21 +0800 CST 如何查找只包含一个文件的目录? 772 有谁知道如何在数千个子目录中搜索仅包含 1 个文件且不超过 1 个文件的所有目录? 关于使用什么工具或简单的代码片段有什么建议吗? powershell 6 个回答 Voted Best Answer user19468 2009-10-15T11:25:17+08:002009-10-15T11:25:17+08:00 在 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 脚本块中。 Zoredache 2009-10-15T10:38:16+08:002009-10-15T10:38:16+08:00 如果这是在 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 中,{} 字符将被每个传递的参数替换。 Sinan Ünür 2009-10-15T17:11:04+08:002009-10-15T17:11:04+08:00 这是一个 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 。 C:\温度\1 C:\Temp\chrome_9999 C:\Temp\CR_3E.tmp Daren Schwenke 2009-10-15T10:36:45+08:002009-10-15T10:36:45+08:00 我认为您可以使用几行代码制作一些东西 File::Find 像这样的东西。 #!/usr/bin/perl use File::Find; my $base_dir = '/'; find( sub { # do stuff on each file here. $filename = $File::Find::name; $dir = $File::Find::dir; }, $base_dir ); ); 编辑:我真的更喜欢 Zoredache 的 find 方法,但您确实将其标记为 perl。 Randal Schwartz 2009-10-29T17:01:50+08:002009-10-29T17:01:50+08:00 解决方案: 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; Adam Mendoza 2012-06-25T14:16:05+08:002012-06-25T14:16:05+08:00 现在,如果你想对这些文件夹做点什么。 $RootFolder = "c:\myfolder" $FoldersWithOnlyOneFile = Get-ChildItem $RootFolder -Recurse | ` Where {$_.PSIsContainer -and @( Get-ChildItem $_.Fullname | Where {!$_.PSIsContainer}).Length -eq 1 ` -and @( Get-ChildItem $_.Fullname | Where {$_.PSIsContainer}).Length -eq 0 } Foreach($folder in $FoldersWithOnlyOneFile) { $Folder.FullName Get-ChildItem $Folder.FullName }
在 PowerShell 中,这是您可以做到的一种方式:
$_.PSIsContainer
目录返回 true,文件返回 false 。该@()
语法确保表达式的结果是一个数组。如果其长度为 1,则该目录中只有一个文件。此示例还使用了嵌套管道,例如Get-ChildItem $_.Fullname | Where {...}
在第一个 Where 脚本块中。如果这是在 Linux 上,我会很想使用这样的命令。
find 命令将打印出所有文件的目录名。然后我们运行排序,然后使用 uniq 的 -c 选项给我们每个目录的文件数。一旦有了每个目录的计数,只需 grep 出值为 1 的目录就应该很容易了。
如果您希望在将目录保持在一行的同时对目录执行操作,则可以通过 awk 将结果通过管道传输到 xargs。例如,要删除每个文件夹:
这会将值为 1 的每个目录打印到一个以空字符结尾的字符串,然后可以将其作为 xargs 的参数。您使用以空字符结尾的字符串,以便按预期处理空格。在 xargs 中,{} 字符将被每个传递的参数替换。
这是一个 Perl 解决方案(在 Windows 上测试):
输出:
我认为您可以使用几行代码制作一些东西
像这样的东西。
编辑:我真的更喜欢 Zoredache 的 find 方法,但您确实将其标记为 perl。
解决方案:
不必要地读取每个目录以计算其中的项目,然后在实际下降时再次读取它(作为
File::Find
框架的一部分)。一个更简单的解决方案是下降,将每个文件的存在计入包含它的目录:
现在,如果你想对这些文件夹做点什么。