是否有一个bash命令来计算匹配模式的文件数量?

例如,我想获取目录中所有文件的计数,这些文件都符合这个模式:log*


当前回答

一个重要的评论

(没有足够的声誉来评论)

这是BUGGY:

ls -1q some_pattern | wc -l

如果shop -s nullglob恰好被设置,它将打印所有常规文件的数量,而不仅仅是带有模式的文件的数量(在CentOS-8和Cygwin上测试)。谁知道他还有什么没用的毛病?

这是正确的,而且更快:

shopt -s nullglob; files=(some_pattern); echo ${#files[@]};

它完成了预期的工作。 运行时间不同。 第一个:CentOS是0.006,Cygwin是0.083(以防小心使用)。 第二:CentOS是0.000,Cygwin是0.003。

其他回答

这里有很多答案,但有些没有考虑在内

包含空格、换行符或控制字符的文件名 以连字符开头的文件名(想象一个名为-l的文件) 隐藏文件,以点开始(如果glob是*.log而不是log*) 匹配glob的目录(例如,一个名为logs的目录匹配log*) 空目录(即结果为0) 非常大的目录(列出所有目录会耗尽内存)

这里有一个解决方案可以处理所有这些问题:

ls 2>/dev/null -Ubad1 -- log* | wc -l

解释:

-U causes ls to not sort the entries, meaning it doesn't need to load the entire directory listing in memory -b prints C-style escapes for nongraphic characters, crucially causing newlines to be printed as \n. -a prints out all files, even hidden files (not strictly needed when the glob log* implies no hidden files) -d prints out directories without attempting to list the contents of the directory, which is what ls normally would do -1 makes sure that it's on one column (ls does this automatically when writing to a pipe, so it's not strictly necessary) 2>/dev/null redirects stderr so that if there are 0 log files, ignore the error message. (Note that shopt -s nullglob would cause ls to list the entire working directory instead.) wc -l consumes the directory listing as it's being generated, so the output of ls is never in memory at any point in time. -- File names are separated from the command using -- so as not to be understood as arguments to ls (in case log* is removed)

shell会将log*扩展到完整的文件列表,如果文件很多,可能会耗尽内存,所以通过grep运行会更好:

ls -Uba1 | grep ^log | wc -l

最后一种方法在不使用大量内存的情况下处理超大文件目录(尽管它使用了子shell)。不再需要-d,因为它只列出当前目录的内容。

这是我的一句话。

 file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)

您可以使用shell函数轻松地定义这样的命令。此方法不需要任何外部程序,也不生成任何子进程。它不会尝试危险的ls解析,并且可以很好地处理“特殊”字符(空格、换行符、反斜杠等等)。它只依赖于shell提供的文件名扩展机制。它至少兼容sh, bash和zsh。

下面的代码行定义了一个名为count的函数,该函数输出调用它的参数的数量。

count() { echo $#; }

只需用所需的模式调用它:

count log*

为了在通配符模式没有匹配的情况下使结果正确,必须在展开时设置shell选项nullglob(或failglob -这是zsh上的默认行为)。可以这样设置:

shopt -s nullglob    # for sh / bash
setopt nullglob      # for zsh

根据您想要计数的内容,您可能还对shell选项dotglob感兴趣。

不幸的是,至少在bash中,不容易在本地设置这些选项。如果你不想全局地设置它们,最直接的解决方案是以这种更复杂的方式使用函数:

( shopt -s nullglob ; shopt -u failglob ; count log* )

如果你想要恢复轻量级语法count log*,或者如果你真的想要避免衍生子shell,你可以按照以下方式进行hack:

# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
    eval "$_count_saved_shopts"
    unset _count_saved_shopts
    echo $#
}
alias count='
    _count_saved_shopts="$(shopt -p nullglob failglob)"
    shopt -s nullglob
    shopt -u failglob
    count'

作为奖励,这个函数有更广泛的用途。例如:

count a* b*          # count files which match either a* or b*
count $(jobs -ps)    # count stopped jobs (sh / bash)

通过将函数转换为可从PATH调用的脚本文件(或等效的C程序),它也可以由find和xargs等程序组成:

find "$FIND_OPTIONS" -exec count {} \+    # count results of a search
ls -1 log* | wc -l

这意味着每行列出一个文件,然后将其输送到单词计数命令,参数切换到计数行。

您可以使用-R选项来查找递归目录中的文件

ls -R | wc -l // to find all the files

ls -R | grep log | wc -l // to find the files which contains the word log

您可以在grep上使用模式