计算"find"结果的最佳方法是什么?



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

为什么不

find <expr> | wc -l

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

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

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

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

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

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


让我们休息一下:

$ 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行)

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 -> 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中找到的解决方案的修改,通过使用print0使find输出分隔符成为NUL字节,并使用'' (NUL字节)作为循环分隔符从中读取,从而正确处理具有非标准名称的文件。

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

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

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

如果不需要临时文件,只有一个很大的警告:您可能会得到(远远)不止一行的输出,因为它将每800~1600个文件执行一次output命令。

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

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

相关内容

最新更新