【问题标题】:What is the best way to count "find" results?计算“查找”结果的最佳方法是什么?
【发布时间】:2013-03-17 19:33:24
【问题描述】:

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

【问题讨论】:

    标签: bash find


    【解决方案1】:

    为什么不

    find <expr> | wc -l
    

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

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

    【讨论】:

    • -1 : 会用换行符打断文件,而且比计算字节要慢 =)
    • 鉴于文件名/换行符限制非常罕见,我认为这不值得反对。慢点 ?可能。鉴于您正在查询文件系统,我怀疑速度差异很小。在我的 10,000 个文件中,我测量了 3 毫秒的差异
    • 'find |wc -l' 和 'find -printf 之间的性能差异。 |wc -c' 非常小。缓存(即,如果您在同一棵树上运行相同的 find 两次)更为重要。恕我直言,使用“wc -l”的解决方案更加直观。
    【解决方案2】:

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

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

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

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


    让我们坐一会儿吧:

    $ 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 标志,则不会更可靠。 ;-)
    • 请注意,您可以通过不引用 -printf '.' 中的点来缩短几纳秒
    • @Jens - 尤其是当您考虑到输入所需的时间时
    • 有了这么小的基准,时间可能受制于其他因素而不是您想要测量的东西。用一棵大树做实验会更有用。但这让我投票赞成实际做 OP 要求的事情。
    【解决方案3】:

    这个解决方案肯定比这里的一些其他find -&gt; 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 的修改,它通过使用 print0find 输出分隔符设置为 NUL 字节并使用 ''(NUL 字节)读取它,从而正确处理具有非标准名称的文件作为循环分隔符。

    【讨论】:

      【解决方案4】:

      这是我 ~/.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'
      

      【讨论】:

        【解决方案5】:

        符合 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
        

        被调用。)

        【讨论】:

          【解决方案6】:

          我需要一些我不会从 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 根本不会影响计数。

          【讨论】:

            猜你喜欢
            • 2023-03-23
            • 1970-01-01
            • 2020-12-04
            • 2020-09-26
            • 2015-08-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多