【问题标题】:Find number of files in each directory in a tree of directories在目录树中查找每个目录中的文件数
【发布时间】:2018-04-01 20:21:41
【问题描述】:

我需要找出树中的哪些目录包含最多的文件(但不是在它们的子目录中)。不应计算目录。

这很容易用 bash、Perl、Python、Tcl 等解决,但用单线解决它很有趣。

我写了以下正确计数的单行代码

ls -Rp1 | grep -vP '\/$' | perl -pe 's/\n/ /' | perl -e '$ln=<>;@ds=split/(?=\.\/)/,$ln;for(@ds){($d,$fs)=split/:/;$fs=~s/^\s+|\s+$//;$c=split/\s+/,$fs;$fc+=$c;print "$c $d\n"}print "Totals: dirs: @{[scalar @ds]}, files: $fc\n"' | sort -n

是否有更优雅的单行解决方案来做到这一点,不一定使用 Perl?

这是多行等效项

#!/usr/bin/perl

$line = <>;
@dirs = split/(?=\.\/)/, $line;

for ( @dirs ) {
    ($dir, $files) = split /:/;
    $files =~ s/^\s+|\s+$//;
    $count = split/\s+/, $files;
    $total_files_count += $count;
    print "$count $dir\n"
}

print "Totals: dirs: @{[scalar @dirs]}, files: $total_files_count\n";

【问题讨论】:

  • 所以您需要从您的层次结构的顶层为每个目录及其所有子目录的总计数文件(不是子目录)? (或者递归地计算每个目录中的文件数?)
  • 我需要给定目录树中每个目录中的文件计数。不是目录及其所有子目录中的文件数 - 这无助于查找文件数量最多的目录。
  • 您的问题应该只包含与问题相关的信息。如果您想对某个答案发表评论,则应在该答案下方添加评论。
  • @Borodin 仅供参考:您的编辑完全改变了我的问题的含义。因此,现在这个问题不仅丢失了一些有用的代码( 与问题相关),而且标记的答案和我最初的示例都不再回答问题,完全做某事 其他。非常感谢!
  • @jcaron:你的评论显然不是“只是为了[我的]信息”,讽刺是不必要的粗俗。我试图澄清你的问题,因为我发现它很难理解。如果我弄错了,我会道歉,但我删除的唯一代码应该是对答案的评论的一部分,根本没有添加到问题中。请解释我如何歪曲你的问题,以便我可以解决它。

标签: linux perl sed find


【解决方案1】:

这样的事情会起作用:

#!/usr/bin/perl

use strict;
use warnings;

countFiles($ARGV[0]);

sub countFiles() {
        my $dir=shift;
        my @list=glob("$dir/*");
        my $count=0;
        for (@list) {
                if (-d) {
                        countFiles($_);
                }
                else {
                        $count++;
                }
        }
        print "directory=$dir, file count=$count\n";
}

或者单排

find . -type f | perl -e 'while(<ARGV>){chomp;s/(.*\/).*$/\1/; $hash{$_}++;}for(keys %hash){print "$_ count=$hash{$_}\n";}'

【讨论】:

  • 谢谢,但这不是我问题的答案。我提到过这个任务很容易通过脚本来解决。我想知道是否有比我的更优雅的单线器或一些现有的 linux cli 工具来完成这项任务。
  • 查看更新,如果找到所有文件,删除文件名并计算目录。
  • 好的,这比我的解决方案优雅得多。我做了一个小改动,在目录名称之前放置 count 以便能够轻松地对结果进行排序:find . -type f | perl -e 'while(&lt;ARGV&gt;){chomp;s/(.*\/).*$/\1/; $hash{$_}++;}for(keys %hash){print "$hash{$_} $_\n";}' | sort -n 问题是这个解决方案在空目录中计算 1 个文件(不正常),并且在只有 1 个文件的目录中计算 1 个文件(好的)。
  • 对不起,我的错,它只是不列出空目录!
  • 无论如何,没有更短的方法可以做到这一点吗?可能不是 Perl。也许用 awk、sed 等等……
【解决方案2】:

一个 Perl “one”-liner,使用核心(和高效)File::Find

perl -MFile::Find -wE'
    find({no_chdir=>1, wanted => sub { ++$dc{$File::Find::dir} if -f }}, "."); 
    printf "%4d => $_\n", $dc{$_} for sort { $dc{$b} <=> $dc{$a} } keys %dc;
'

打印(正确)每个目录(而不是其子目录)中“普通”文件 (-f) 的计数

45 =>。 7 => ./dir/sub_dir_1 4 => ./目录 3 => ./another_dir 2 => ./dir/sub_dir_2

或者使用File::Find::Rule,它有更好的界面和不同的输出格式

perl -MList::Util=max -MFile::Find::Rule -wE'
    @dirs   = File::Find::Rule->directory->in(".");
    $dc{$_} = File::Find::Rule->file->maxdepth(1)->in($_) for @dirs;
    @skeys = sort { $dc{$b} <=> $dc{$a} } keys %dc;
    $ml = max map { length } @skeys; 
    for (@skeys) { printf "%${ml}s => $dc{$_}\n", $_ }
'

最后三行和-MList::Util=max 仅用于输出格式。打印

. => 47 目录/子目录_1 => 7 目录 => 4 另一个目录 => 3 目录/子目录_2 => 2 空目录 => 0

【讨论】:

    【解决方案3】:

    这不行吗?

    find . -type f | sed -e 's/[^\\/]*$//' | sort | uniq -c | sort -rn | head -10
    

    PS:如果意图是最短的代码,您可能希望将挑战发布到代码高尔夫。

    【讨论】:

    • 哦,这真是有前途!我会玩一点,然后给你反馈。
    • 好的,非常感谢!无法想象除了用于此类任务的工具之外,可能会有明显更短的解决方案。无论如何,在将您的解决方案标记为“已回答”之前,我想再多花点时间。
    • Perl 等效项(您的解决方案仍然更短):find . -type f | perl -pe 's|[^/]*$|\n|' | sort | uniq -c | sort -n
    • 在您的解决方案中,我们不必在 sed 中使用斜杠。这也有效:find . -type f | sed -e 's|[^/]*$||' | sort | uniq -c | sort -n。你能更新你的答案吗?
    • 已将 sed 替换为 find-printf。另外,我们不需要在find 中为当前目录指定句点:find -type f -printf "%h\n" | sort | uniq -c | sort -n
    猜你喜欢
    • 2022-07-21
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 2019-12-17
    相关资源
    最近更新 更多