bash - 查找结果的最佳方法是什么?

Mec*_*MK1 83 bash find

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

Bri*_*new 120

为什么不

find <expr> | wc -l
Run Code Online (Sandbox Code Playgroud)

作为简单的便携式解决方案 您的原始解决方案会为找到的每个文件生成一个新进程 printf,而且这非常昂贵(正如您刚刚发现的那样).

请注意,如果你有嵌入换行符的文件名,这将会超额计算,但如果你有,那么我怀疑你的问题运行得更深一些:-)

  • 我认为,鉴于文件名/换行限制非常罕见*并且*在上面注明,我认为这保证了一个downvote.慢点 ?也许.鉴于您正在查询文件系统,我怀疑速度差异很小.在我的10,000个文件中,我测量3ms的差异 (18认同)
  • -1:将使用换行符中断文件,并且比计算bytes =更慢 (8认同)
  • 'find <expr> | wc -l'和'find <expr> -printf之间的性能差异.| wc -c'非常小.缓存(即,如果在同一棵树上运行相同的两次)则更为重要.恕我直言,"wc -l"的解决方案更加直观. (5认同)

Gil*_*not 65

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

find <expr> -type f -printf '.' | wc -c
Run Code Online (Sandbox Code Playgroud)

它比计算线条更可靠,更快捷.

请注意,我使用的是find's printf,而不是外部命令.


让我们坐一会儿:

$ ls -1
a
e
l
ll.sh
r
t
y
z
Run Code Online (Sandbox Code Playgroud)

我的代码段基准:

$ time find -type f -printf '.' | wc -c
8

real    0m0.004s
user    0m0.000s
sys     0m0.007s
Run Code Online (Sandbox Code Playgroud)

全线:

$ time find -type f | wc -l
8

real    0m0.006s
user    0m0.003s
sys     0m0.000s
Run Code Online (Sandbox Code Playgroud)

所以我的解决方案更快=)(重要的部分是real线)

  • 请注意,您可以通过不引用`-printf'中的点来减少几纳秒 (7认同)
  • 不等同,它更可靠=) (6认同)
  • 如果您的平台不支持查找-printf标志,则不可靠.;-) (6认同)
  • 如此小的基准,时间可能由其他因素决定,而不是你想要衡量的东西.使用大树的实验会更有用.但这得到了我实际做OP所要求的投票. (6认同)
  • @Jens - 尤其是考虑到输入时间所需的时间 (5认同)
  • 任何阅读这些评论的人都应该知道,所有关于命令速度的争吵在很大程度上都是在浪费时间。尽可能花时间编写最接近 O(1) 到 O(n) 的可读代码,而不是对命令本身进行计数。我曾让同事们为这些胡说八道而争论不休,同时讽刺地编写了 * 不必要地 * 在指数时间内运行的代码。 (4认同)
  • @AdrienHorgnies,文件名中可以​​包含换行符。计算点数“绝对”更可靠。 (2认同)

Qua*_*odo 10

符合 POSIX 标准且防换行:

find /path -exec printf %c {} + | wc -c
Run Code Online (Sandbox Code Playgroud)

而且,根据我在 中的测试/,它甚至不比其他解决方案慢两倍,这些解决方案要么不防换行,要么不可移植。

注意+代替\;. 这对于性能至关重要,因为每个文件名\;生成一个命令,而为单个命令提供尽可能多的文件名。(并且在可能存在太多参数的情况下,Find 会根据需要智能地生成新的 Printfs 来应对它,所以就好像printf+printf

{ 
  printf %c very long argument list1
  printf %c very long argument list2
  printf %c very long argument list3 
} | wc -c
Run Code Online (Sandbox Code Playgroud)

被称为。)


Joh*_*n B 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
Run Code Online (Sandbox Code Playgroud)

它只是对 BashGuide 中找到的解决方案的修改,该解决方案通过使用 将find输出定界符设为NUL 字节print0,并使用''(NUL 字节) 作为循环定界符从中读取来正确处理具有非标准名称的文件。


小智 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'
Run Code Online (Sandbox Code Playgroud)