我目前的解决方案是find <expr> -exec printf '.' \; | wc -c
,但是当有超过 10000 个结果时,这需要很长时间。有没有更快/更好的方法来做到这一点?
6 回答
为什么不
find <expr> | wc -l
作为一个简单的便携式解决方案?您最初的解决方案是为找到的每个单独文件生成一个新进程 printf
,这非常昂贵(正如您刚刚发现的那样)。
请注意,如果您的文件名嵌入了换行符,这将多计,但如果您有,那么我怀疑您的问题会更深一些。
试试这个(需要find
的-printf
支持):
find <expr> -type f -printf '.' | wc -c
这将比数行更可靠、更快捷。
请注意,我使用find
's printf
,而不是外部命令。
让我们坐一会儿:
$ ls -1
a
e
l
ll.sh
r
t
y
z
我的片段基准:
$ 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
行)
这个解决方案肯定比find -> wc
这里的一些其他解决方案慢,但是如果您除了计算文件名之外还倾向于对文件名执行其他操作,您可以read
从find
输出中获取。
n=0
while read -r -d ''; do
((n++)) # count
# maybe perform another act on file
done < <(find <expr> -print0)
echo $n
它只是对BashGuide 中找到的解决方案find
的修改,该解决方案通过使用 将输出定界符设置为 NUL 字节print0
并使用''
(NUL 字节) 作为循环定界符从中读取来正确处理具有非标准名称的文件。
这是我的countfiles
功能~/.bashrc
(它相当快,应该适用于 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
in every find 命令根本不会影响计数。