【问题标题】:Find count of files matching a pattern in a directory in linux在linux的目录中查找与模式匹配的文件数
【发布时间】:2014-02-04 06:05:27
【问题描述】:

我是 linux 新手。我在 linux 中有一个包含大约 250,000 个文件的目录 我需要找到与模式匹配的文件数。

我尝试使用以下命令:

ls -1 20061101-20131101_kh5x7tte9n_2010_* | wc -l

我收到以下错误消息:

-bash: /bin/ls: Argument list too long
0

请帮忙。提前致谢

【问题讨论】:

    标签: regex linux bash find ls


    【解决方案1】:

    为此使用find 可能会更好:

    find . -name "pattern_*" -printf '.' | wc -m
    

    在您的具体情况下:

    find . -maxdepth 1 -name "20061101-20131101_kh5x7tte9n_2010_*" -printf '.' | wc -m
    

    find 将返回符合条件的文件列表。 -maxdepth 1 将使搜索仅在路径中完成,没有子目录 (thanks Petesh!)。 -printf '.' 将为每个匹配项打印一个点,因此带有新行的名称不会使 wc -m 中断。

    然后wc -m 将指示与文件数匹配的字符数。


    两种可能方案的性能比较:

    让我们用这个模式创建 10 000 个文件:

    $ for i in {1..10000}; do touch 20061101-20131101_kh5x7tte9n_201_$i; done
    

    然后将得到结果的时间与ls -1 ...find ...进行比较:

    $ time find . -maxdepth 1 -name "20061101-20131101_kh5x7tte9n_201_*" | wc -m
    10000
    
    real    0m0.034s
    user    0m0.017s
    sys     0m0.021s
    
    $ time ls -1 | grep 20061101-20131101_kh5x7tte9n_201 | wc -m
    10000
    
    real    0m0.254s
    user    0m0.245s
    sys     0m0.020s
    

    find 快 5 倍!但是如果我们使用ls -1fthanks Petesh again!),那么ls甚至比find还要快:

    $ time ls -1f | grep 20061101-20131101_kh5x7tte9n_201 | wc -m
    10000
    
    real    0m0.023s
    user    0m0.020s
    sys     0m0.012s
    

    【讨论】:

    • 为了防止递归到子目录,您可以使用-maxdepth 1(如果该版本的 find 支持)
    • ls 有输出前排序的坏习惯,你应该用ls -1 -f 测试以获得与 find 类似的行为进行性能评估
    • 很有趣,@Petesh,不知道。我已经测试了性能,对我来说ls -1f 甚至比find 还要快。
    • 如果您使用 -printf '.' 技巧,您应该计算字符 (wc -m) 而不是行数。或者,在点后添加一个换行符 (-printf '.\n')。
    • --count (-c) 用于grep 并跳过wc 怎么样?我期望性能提升。 (也是一个更简单的表达式。)同样,出于同样的原因,我希望 find-namels|grep 快,但显然不是......
    【解决方案2】:

    您得到“参数太长”,因为 shell 将您的模式扩展到文件列表。 试试:

    find  -maxdepth 1 -name '20061101-20131101_kh5x7tte9n_2010_*' |wc -l
    

    请注意 - 模式用引号括起来以防止外壳扩展

    【讨论】:

      【解决方案3】:

      试试这个:

      ls -1 | grep 20061101-20131101_kh5x7tte9n_2010_ | wc -l
      

      【讨论】:

        【解决方案4】:

        MacOS/OS X 命令行解决方案

        如果您尝试在 Mac 上的命令行中执行此操作,您很快就会发现 find does not support -printf 选项。

        要达到与fedorqui-supports-monica 提出的解决方案相同的结果,请尝试以下操作:

        find . -name "pattern_*" -exec stat -f "." {} \; | wc -l
        

        这将找到与您输入的模式匹配的所有文件,在换行符中为每个文件打印一个.,然后最后计算行数并输出该数字。

        要将搜索深度限制在当前目录,请将-maxdepth 1 添加到命令中,如下所示:

        find . -maxdepth 1 -name "196288.*" -exec stat -f "." {} \; | wc -l
        

        【讨论】:

          【解决方案5】:

          你通常应该avoid ls in scripts,事实上,在shell函数中执行计算将避免“参数列表太长”错误,因为没有exec边界,所以ARGV_MAX限制不会出现玩。

          number_of_files () {
              if [ -e "$1" ]; then
                  echo "$#"
              else
                  echo 0
              fi
          }
          

          条件防止 glob 根本不被扩展(这是开箱即用的默认设置;在 Bash 中,您可以 shopt -s nullglob 将不匹配任何文件的通配符扩展为空字符串)。

          试试看:

          number_of_files 20061101-20131101_kh5x7tte9n_2010_*
          

          【讨论】:

            【解决方案6】:
            ls -1 | grep '20061101-20131101_kh5x7tte9n_2010_*' | wc -l
            

            上一个答案没有包含搜索条件的引号,也没有 * 通配符。

            【讨论】:

            • 这基本上是对先前答案的重复,而且它不起作用。
            • 这会混淆 shell 通配符和正则表达式。 grep 支持后者,并且会在任何子字符串上找到匹配项,因此尾随通配符是不必要的,也不代表您的想法。我支持您通常应该在正则表达式周围使用引号的想法,但在这种特殊情况下,没有必要,并且不正确的正则表达式会破坏答案。作为记录,通配符*(不能被引用)对应于正则表达式.*
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-19
            • 1970-01-01
            • 1970-01-01
            • 2014-05-02
            • 2013-10-19
            • 1970-01-01
            相关资源
            最近更新 更多