计算“查找”结果的最佳方法是啥?

Posted

技术标签:

【中文标题】计算“查找”结果的最佳方法是啥?【英文标题】:What is the best way to count "find" results?计算“查找”结果的最佳方法是什么? 【发布时间】:2013-03-17 19:33:24 【问题描述】:

我当前的解决方案是find <expr> -exec printf '.' \; | wc -c,但是当结果超过 10000 个时,这需要很长时间。有没有更快/更好的方法来做到这一点?

【问题讨论】:

【参考方案1】:

为什么不

find <expr> | wc -l

作为一个简单的便携式解决方案?您最初的解决方案是为找到的每个单独文件生成一个新进程printf,这非常昂贵(正如您刚刚发现的那样)。

请注意,如果您的文件名中嵌入了换行符,这将多计,但如果您有,那么我怀疑您的问题会更深一些。

【讨论】:

-1 : 会用换行符打断文件,而且比计算字节要慢 =) 鉴于文件名/换行符限制非常罕见,我认为这不值得反对。慢点 ?可能。鉴于您正在查询文件系统,我怀疑速度差异很小。在我的 10,000 个文件中,我测量了 3 毫秒的差异 'find |wc -l' 和 'find -printf 之间的性能差异。 |wc -c' 非常小。缓存(即,如果您在同一棵树上运行相同的 find 两次)更为重要。恕我直言,使用“wc -l”的解决方案更加直观。【参考方案2】:

试试这个(需要 find-printf 支持):

find <expr> -type f -printf '.' | wc -c

这将比数行更可靠和更快。

请注意,我使用的是findprintf,而不是外部命令。


让我们坐一会儿吧:

$ ls -1
a
e
l
ll.sh
r
t
y
z

我的 sn-p 基准测试:

$ time find -type f -printf '.' | wc -c
8

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

全行:

$ time find -type f | wc -l
8

real    0m0.006s
user    0m0.003s
sys     0m0.000s

所以我的解决方案更快 =)(重要的部分是 real 行)

【讨论】:

不等价,更可靠=) 如果您的平台不支持要查找的 -printf 标志,则不会更可靠。 ;-) 请注意,您可以通过不引用 -printf '.' 中的点来缩短几纳秒 @Jens - 尤其是当您考虑到输入所需的时间时 有了这么小的基准,时间可能受制于其他因素而不是您想要测量的东西。用一棵大树做实验会更有用。但这让我投票赞成实际做 OP 要求的事情。【参考方案3】:

这个解决方案肯定比这里的一些其他find -&gt; wc 解决方案慢,但是如果您除了计算文件名之外还倾向于对文件名做其他事情,您可以从find 输出中read

n=0
while read -r -d ''; do
    ((n++)) # count
    # maybe perform another act on file
done < <(find <expr> -print0)
echo $n

它只是对 BashGuide 中 a solution 的修改,它通过使用 print0find 输出分隔符设置为 NUL 字节并使用 ''(NUL 字节)读取它,从而正确处理具有非标准名称的文件作为循环分隔符。

【讨论】:

【参考方案4】:

这是我 ~/.bashrc 中的 countfiles 函数(它相当快,应该适用于 Linux 和 FreeBSD find,并且不会被包含换行符的文件路径所迷惑;最后的 wc 只计算 NUL字节):

countfiles () 
 
   command find "$1:-." -type f -name "$2:-*" -print0 | 
       command tr -dc '\0' | command wc -c;
return 0


countfiles

countfiles ~ '*.txt'

【讨论】:

【参考方案5】:

符合 POSIX 且防换行:

find /path -exec printf %c  + | wc -c

而且,根据我在 / 中的测试,甚至不比其他解决方案慢两倍,这些解决方案要么不防换行,要么不可移植。

注意+ 而不是\;。这对性能至关重要,因为\; 为每个文件名生成一个printf 命令,而+ 为单个printf 命令提供尽可能多的文件名。 (并且在参数过多的可能情况下,Find 会根据需要智能地生成新的 Printfs 来应对它,所以它就像

 
  printf %c very long argument list1
  printf %c very long argument list2
  printf %c very long argument list3 
 | wc -c

被调用。)

【讨论】:

【参考方案6】:

我需要一些我不会从 find 获取所有输出的东西,因为其他一些命令运行也会打印东西。

不需要临时文件,这只能通过一个很大的警告来实现:您可能会得到(远)多于一行的输出,因为它会为每 800~1600 个文件执行一次输出命令。

find . -print -exec sh -c 'printf %c "$@" | wc -c' '' '' + # just print the numbers
find . -print -exec sh -c 'echo "Processed `printf %c "$@" | wc -c` items."' '' '' +

生成这个结果:

Processed 1622 items.
Processed 1578 items.
Processed 1587 items.

另一种方法是使用临时文件:

find . -print -fprintf tmp.file .
wc -c <tmp.file # using the file as argument instead causes the file name to be printed after the count

echo "Processed `wc -c <tmp.file` items." # sh variant
echo "Processed $(wc -c <tmp.file) items." # bash variant

每个查找命令中的-print 根本不会影响计数。

【讨论】:

以上是关于计算“查找”结果的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

创建聚合表的最佳方法是啥?

用openGL绘制频谱图的最佳方法是啥

计算用于运输的最佳包装箱尺寸的最佳方法是啥? [复制]

在 iOS 中处理静默推送通知的最佳方法是啥

计算热门话题或标签的最佳方法是啥?

在 Android 手机中计算与 GPS 距离的最佳方法是啥?