有没有比“发现”更快的东西。| wc -l`计算目录中的文件?


8

经常,我必须计算目录中文件的数量,有时这会达到数百万。

有没有比枚举和计数更好的方法了find . | wc -l?您可以在ext3 / 4上进行一些类型的文件系统调用吗,这些调用的I / O强度较小?


3
您不仅在计算文件,还在计算目录。如果只想计数文件,
则要

目录是一种文件,设备,符号链接和套接字也是如此。常规文件是文件的子集。
Toby Speight

1
您给出的示例建议您要递归计数-如果不需要,则需要find -maxdepth 1。请注意,使用当前方法,您将对包含换行符的任何名称进行重复计数。
Toby Speight

Answers:


13

不是根本的提速,但至少是:)

find . -printf \\n | wc -l

您真的不需要传递文件名列表,只需换行即可。当目录缓存在RAM中时,在我的Ubuntu 12.04.3上,此变体的速度提高了约15%。此外,此变体将与包含换行符的文件名一起正常使用。

有趣的是,此变体似乎比上述变体慢一点:

find . -printf x | wc -c

特例-但速度很快

如果目录位于其自己的文件系统上,则可以简单地计算索引节点:

df -i .

如果除已计数目录外的其他目录中的目录和文件数没有太大变化,则可以从当前df -i结果中减去该已知数。这样,您将能够非常快速地计算文件和目录。


“这个变体快了15%...”让我想知道您是否有一些方便的技巧来计时这些时间?
Brian Z

4
@BrianZ:您可以通过在命令前加上时间来对命令进行计时。time find /usr/src/ -printf \\n | wc -l,您可以使用sudo sync && sudo sysctl -w vm.drop_caches=3
MattPark

因此,我发现前两个选项中的任何一个在没有缓存的情况下,速度都能稳定地增长2%。是的,这是一种非常酷的方法。如果为您的环境设置了索引节点,那么绝对是最好的方法。我没考虑过
MattPark 2013年

-printf x要一样-printf '\0'吗?我看不到文档中提到的内容。
CMCDragonkai

@CMCDragonkai:动作与C中-printfprintf()功能相似,主要区别在于%指令的含义不同。将为找到的每个文件调用该操作。这意味着-printf x将为x找到的每个文件打印字符(尝试!),并为找到的每个文件-printf '\0'打印字符NULL(ASCII代码0)。-printf '\0'没有特别的意义。wc -c在此答案的示例中,两者将相同地工作。
pabouk

3

我已经为这个目的写了ffcnt。它使用fiemapioctl 检索目录本身的物理偏移量,然后按多次顺序遍历计划目录遍历以减少随机访问。您是否真正获得了加速比,find | wc 取决于几个因素:

  • 文件系统类型:支持fiemapioctl的文件系统(例如ext4)将受益最大
  • 随机访问速度:HDD的收益远大于SSD
  • 目录布局:嵌套目录数越多,优化潜力越大

进行访问(否则重新安装)relatime甚至nodiratime可能提高速度(对于所有方法),否则访问会导致元数据更新。


最后一句话值得一提!我认为,如果您添加了程序工作原理的摘要,则将改善与程序的链接。如果链接的资源发生任何不良情况,我们更喜欢自己填写完整的答案(当然,当然也要保留链接)。
Toby Speight

2

实际上,在我的系统(Arch Linux)上,此命令

   ls -A | wc -l

比以上所有方法都快:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s

我认为ls的问题在于,它经常返回类似/bin/ls: Argument list too long使用globbing的结果,但是它又可以像find一样递归地运行,所以也许这是要考虑的事情,如果不需要,请不要使用find。
MattPark 2013年

对此进行评论似乎太晚了(很多年),但是ls -A仅列出当前目录中的文件,而find没有-maxdepth 1参数将对所有子目录进行递归搜索。
卢西亚诺
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.