118

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

4

6 回答 6

155

为什么不

find <expr> | wc -l

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

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

于 2013-03-27T16:10:39.660 回答
97

试试这个(需要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行)

于 2013-03-27T16:14:23.190 回答
6

这个解决方案肯定比find -> wc这里的一些其他解决方案慢,但是如果您除了计算文件名之外还倾向于对文件名执行其他操作,您可以readfind输出中获取。

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 字节) 作为循环定界符从中读取来正确处理具有非标准名称的文件。

于 2014-01-11T10:51:31.790 回答
5

这是我的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'
于 2013-03-27T17:04:19.103 回答
2

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

被称为。)

于 2021-09-25T12:29:48.683 回答
0

我需要一些我不会从 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

-printin every find 命令根本不会影响计数。

于 2021-12-03T15:21:13.030 回答