在第一层中找到包含最多文件/目录的前50个目录?


21

如何使用find生成包含最多文件数量的目录列表。我希望列表从最高到最低。我只希望列表深1级,并且通常从文件系统的顶部(即)运行此命令/


不同的问题(实际上是相同的,但提出的问题有所不同),但是答案也不会解决您的问题吗?unix.stackexchange.com/questions/117093/…–
Patrick

也相关-stackoverflow.com/questions/15216370/…。这是我最初基于inode问题提出的答案,尽管我认为我的方法相对于inode问题有所改进。
Graeme 2014年

@Patrick-这是一个仅容纳Graemes A的已装载Q。
slm

@slm然后我真的不明白为什么这不是重复的。他的答案似乎只是对另一个问题的详尽阐述。因此,对于同一件事,我们现在有3个问题。我认为我的链接上的答案也更干净。为找到的每个目录启动一个外壳感觉很脏。
帕特里克

1
@Patrick,我对答案进行了重新设计,以使GNU解决方案不会为每个目录启动新的shell。不过请注意,这是可移植地处理任何文件名的标准解决方案。
Graeme 2014年

Answers:


17

使用GNU工具:

find / -xdev -type d -print0 |
  while IFS= read -d '' dir; do
    echo "$(find "$dir" -maxdepth 1 -print0 | grep -zc .) $dir"
  done |
  sort -rn |
  head -50

这使用两个find命令。第一个查找目录并将其通过管道传送到while循环,然后为每个目录运行下一个查找。第二个列出了第一级中的所有子文件/目录,并对其进行了grep计数。该grep-print0与第二个find使用,因为wc没有一个-z等价的。这样可以避免使用换行符的文件名被计算两次(尽管使用wc和没有-print0太大的区别)。

第二个的结果find放置在to的参数中,echo因此它和目录名可以轻松地放置在同一行上(该$(..)结构会自动修剪末尾的换行符grep)。然后按数字对行进行排序,并用表示最大的50个数字head

请注意,这还将包括安装点的顶级目录。解决此问题的一种简单方法是使用绑定安装,然后使用安装目录。去做这个:

sudo mount --bind / /mnt

更具可移植性的解决方案为每个目录使用不同的Shell实例(也在此处回答):

find / -xdev -type d -exec sh -c '
  echo "$(find "$0" | grep "^$0/[^/]*$" | wc -l) $0"' {} \; |
  sort -rn |
  head -50

样本输出:

9225 /var/lib/dpkg/info
6322 /usr/share/qt4/doc/html
4927 /usr/share/man/man3
2301 /usr/share/man/man1
2097 /usr/share/doc
2097 /usr/bin
1863 /usr/lib/x86_64-linux-gnu
1679 /var/cache/apt/archives
1628 /usr/share/qt4/doc/src/images
1614 /usr/share/qt4/doc/html/images
1308 /usr/share/scilab/modules/overloading/macros
1083 /usr/src/linux-headers-3.13-1-common/include/linux
1071 /usr/src/linux-headers-3.13-1-amd64/include/config
847 /usr/include/qt4/QtGui
774 /usr/include/qt4/Qt
709 /usr/share/man/man8
616 /usr/lib
611 /usr/share/icons/oxygen/32x32/actions
608 /usr/share/icons/oxygen/22x22/actions
598 /usr/share/icons/oxygen/16x16/actions
579 /usr/share/bash-completion/completions
574 /usr/share/icons/oxygen/48x48/actions
570 /usr/share/vim/vim74/syntax
546 /usr/share/scilab/modules/m2sci/macros/sci_files
531 /usr/lib/i386-linux-gnu/wine/wine
530 /usr/lib/i386-linux-gnu/wine/wine/fakedlls
496 /etc/ssl/certs
457 /usr/share/mime/application
454 /usr/share/man/man2
450 /usr/include/qt4/QtCore
443 /usr/lib/python2.7
419 /usr/src/linux-headers-3.13-1-common/include/uapi/linux
413 /usr/share/fonts/X11/misc
413 /usr/include/linux
375 /usr/share/man/man5
374 /usr/share/lintian/overrides
372 /usr/share/cmake-2.8/Modules
370 /usr/share/fonts/X11/75dpi
370 /usr/share/fonts/X11/100dpi
356 /usr/share/icons/gnome/24x24/actions
356 /usr/share/icons/gnome/22x22/actions
356 /usr/share/icons/gnome/16x16/actions
353 /usr/share/icons/gnome/48x48/actions
353 /usr/share/icons/gnome/32x32/actions
341 /usr/lib/ghc/ghc-7.6.3
326 /usr/sbin
324 /usr/share/scilab/modules/compatibility_functions/macros
324 /usr/share/scilab/modules/cacsd/macros
320 /usr/share/terminfo/a
319 /usr/share/i18n/locales

11

更新:我做了下面的所有事情,这很酷,但是我想出了一种更好的通过inode使用对目录进行排序的方法:

du --inodes -S | sort -rh | sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/\1...\2/;p}'

如果要保留在同一文件系统中,请执行以下操作:

du --inodes -xS

这是一些示例输出:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
...
519     /usr/lib/python2.7/site-packages/bzrlib
516     /usr/include/KDE
498     /usr/include/qt/QtCore
487     /usr/lib/modules/3.13.6-2-MANJARO/build/include/config
484     /usr/src/linux-3.12.14-2-MANJARO/include/config

现在使用LS:

一些人提到他们没有最新的coreutils,并且--inodes选项对他们不可用。所以,这是ls:

sudo ls -AiR1U ./ | 
sed -rn '/^[./]/{h;n;};G;
    s|^ *([0-9][0-9]*)[^0-9][^/]*([~./].*):|\1:\2|p' | 
sort -t : -uk1.1,1n |
cut -d: -f2 | sort -V |
uniq -c |sort -rn | head -n10

这为我提供了与du命令几乎相同的结果:

杜:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
1.9K    /usr/share/fonts/100dpi
1.9K    /usr/share/doc/arch-wiki-markdown
1.6K    /usr/share/fonts/TTF
1.6K    /usr/share/dolphin-emu/sys/GameSettings
1.6K    /usr/share/doc/efl/html

LS:

14686   /usr/share/man/man3:
4322    /usr/lib:
3653    /usr/bin:
2457    /usr/share/man/man1:
1897    /usr/share/fonts/100dpi:
1897    /usr/share/fonts/75dpi:
1890    /usr/share/doc/arch-wiki-markdown:
1613    /usr/include:
1575    /usr/share/doc/efl/html:
1556    /usr/share/dolphin-emu/sys/GameSettings:

我认为include事情只取决于程序首先查看哪个目录-因为它们是相同的文件,并且经过硬链接。有点喜欢上面的事情。我对此可能是错的-我欢迎改正...

这样做的基本方法是,我lssed.接下来的内容中用包含目录名称的替换文件名中的每个文件名...好吧,我自己有点模糊。我可以肯定,它可以准确计数文件,如您在此处看到的:

% _ls_i ~/test
> 100 /home/mikeserv/test/realdir
>   2 /home/mikeserv/test
>   1 /home/mikeserv/test/linkdir

杜德莫

% du --version
> du (GNU coreutils) 8.22

创建一个测试目录:

% mkdir ~/test ; cd ~/test
% du --inodes -S
> 1       .

一些子目录:

% mkdir ./realdir ./linkdir
% du --inodes -S
> 1       ./realdir
> 1       ./linkdir
> 1       .

制作一些文件:

% printf 'touch ./realdir/file%s\n' `seq 1 100` | . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

一些硬链接:

% printf 'n="%s" ; ln ./realdir/file$n ./linkdir/link$n\n' `seq 1 100` | 
    . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

查看硬链接:

% cd ./linkdir
% du --inodes -S
> 101

% cd ../realdir
% du --inodes -S
> 101

他们一个人算,但上一个目录...

% cd ..
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

然后从下面运行我的运行脚本,然后:

> 100     /home/mikeserv/test/realdir
> 100     /home/mikeserv/test/linkdir
> 2       /home/mikeserv/test

和格雷姆的:

> 101 ./realdir
> 101 ./linkdir
> 3 ./

因此,我认为这表明计数inode的唯一方法是使用inode。而且由于对文件进行计数意味着对inode进行计数,因此您不能对inode进行双重计数-要准确地对文件进行计数,就不能对inode进行多次计数。

旧:

我发现它更快,并且可移植:

sh <<-\CMD
    { echo 'here='"$PWD"
        printf 'cd "${here}/%s" 2>/dev/null && {
                set -- 
                for glob in ".[!.]*" "[!.]*" ; do
                    set -- $glob "$@" && 
                        [ -e "./$1" ] || shift
                done    
                printf "%%s\\t%%s\\n" $# "$PWD"
        }\n' $( find . -depth -type d 2>/dev/null )
    } | . /dev/stdin |
    sort -rn | 
    sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/\1...\2/;p}'
CMD

不必-exec每个目录都使用-它只使用一个shell进程和一个ell进程find。我必须set -- $glob正确地包括.hidden文件和所有其他内容,但是它非常接近而且非常快。您只需cd进入根目录中的任意位置即可进行检查,然后退出。

这是我的输出示例/usr

14684   /usr/share/man/man3
4322    /usr/lib
3650    /usr/bin
2454    /usr/share/man/man1
1897    /usr/share/fonts/75dpi
...
557     /usr/share/gtk-doc/html/gtk3
557     /usr/share/doc/elementary/latex
539     /usr/lib32/wine/fakedlls
534     /usr/lib/python2.7/site-packages/bzrlib
500     /usr/lib/python3.3/test

我还在sed底部使用它修剪到前50个结果。head当然会更快,但如有必要,我还会修剪每行:

...   
159     /home/mikeserv/.config/hom...hhkdoolnlbekcfllmednbl/4.30_0/plugins
154     /home/mikeserv/.config/hom...odhpcledpamjachpmelml/1.3.11_0/js/ace
...

坦率地说,这很粗糙,但这是一个想法。另外原油设备我用的是倾销2>stderr两个findcd2>/dev/null。这比查看没有root访问权限无法读取的目录的权限错误更干净-也许我应该将其指定为find。好吧,这是一个正在进行的工作。

好的,所以我确实像这样修复了外壳问题:

for glob in ".[!.]*" "[!.]*" ; do
    set -- $glob "$@" && 
        [ -e "./$1" ] || shift
done    

我实际上是在问一个如何完成它的问题,但是当我输入问题标题时,该网站向我指出了一个建议的相关问题,斯蒂芬妮已经在其中权衡了一下。这样很方便。显然,[^.],尽管得到了很好的支持,但它不是可移植的,您必须使用!bang.I在Stephane的注释中发现的。

无论如何,显然,仅拉入隐藏文件是不够的。所以我不得不set两次,以避免在位置上搜索文字$glob。不过,它似乎丝毫不影响性能,并且可以可靠地将目录中的每个文件添加到文件中。


@Graeme您知道,尽管我们的解决方案都没有实际处理inode。我们列出的许多文件很可能彼此硬链接。我想我可以用ls -i... 来做...我想...可能grep...也许-好吧,您正在使用-xdev,这是一个开始... uniq以及sort
mikeserv 2014年

du您正在运行哪个版本?我du没有--inodes选择。
Patrick

@Patrick-可能要更新-但我更新了帖子。
mikeserv

这是一个令人讨厌的功能:-)我正在运行8.21。好像它是在2013
Patrick

另外,如果您不介意的话,可以将其发布在此问题上。我认为我不会接受它,因为它不是很便携,但是我会赞成,对这个问题有另一个解决方案将是很好的。
Patrick

1

为什么不使用诸如KDirStat之类的东西虽然它最初是为KDE编写的,但是它也可以与GNOME一起使用。


1
寻找命令行方法。
slm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.