计算“查找”结果的最佳方法是啥?
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试试这个(需要 find
的 -printf
支持):
find <expr> -type f -printf '.' | wc -c
这将比数行更可靠和更快。
请注意,我使用的是find
的printf
,而不是外部命令。
让我们坐一会儿吧:
$ 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 -> 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 的修改,它通过使用 print0
将 find
输出分隔符设置为 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
根本不会影响计数。
【讨论】:
以上是关于计算“查找”结果的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章