【发布时间】:2013-03-17 19:33:24
【问题描述】:
我当前的解决方案是find <expr> -exec printf '.' \; | wc -c,但是当结果超过 10000 个时,这需要很长时间。有没有更快/更好的方法来做到这一点?
【问题讨论】:
我当前的解决方案是find <expr> -exec printf '.' \; | wc -c,但是当结果超过 10000 个时,这需要很长时间。有没有更快/更好的方法来做到这一点?
【问题讨论】:
为什么不
find <expr> | wc -l
作为一个简单的便携式解决方案?您最初的解决方案是为找到的每个单独文件生成一个新进程printf,这非常昂贵(正如您刚刚发现的那样)。
请注意,如果您的文件名中嵌入了换行符,这将多计,但如果您有,那么我怀疑您的问题会更深一些。
【讨论】:
试试这个(需要 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 '.' 中的点来缩短几纳秒
这个解决方案肯定比这里的一些其他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 字节)读取它,从而正确处理具有非标准名称的文件作为循环分隔符。
【讨论】:
这是我 ~/.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'
【讨论】:
符合 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
被调用。)
【讨论】:
我需要一些我不会从 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 根本不会影响计数。
【讨论】: