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

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


当前回答

你可以用bash安全地做到这一点(即不会被名称中有空格或\n的文件所bug):

$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}

您需要启用nullglob,以便在没有匹配的文件时不会在$logfiles数组中获得*.log文本。(参见如何“撤消”一个“set -x”?有关如何安全重置的示例。)

其他回答

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

包含空格、换行符或控制字符的文件名 以连字符开头的文件名(想象一个名为-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中工作,而不仅仅是bash:

ls -1q log* | wc -l

Ls -1q将为每个文件提供一行,即使它们包含空格或换行符等特殊字符。

输出被输送到wc -l,它计算行数。

对于递归搜索:

find . -type f -name '*.log' -printf x | wc -c

Wc -c将计算find输出中的字符数,而-printf x告诉find为每个结果打印单个x。这避免了包含换行符等奇怪名称的文件的任何问题。

对于非递归搜索,这样做:

find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c

如果您有很多文件,并且不想使用优雅的shopt -s nullglob和bash数组解决方案,您可以使用find等,只要不打印文件名(可能包含换行符)。

find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l

这将找到所有匹配log*且不以。*开头的文件-“not name .*”是冗余的,但重要的是要注意,“ls”的默认值是不显示点文件,但find的默认值是包含它们。

这是一个正确答案,可以处理任何类型的文件名,因为文件名永远不会在命令之间传递。

但是,shopt nullglob答案是最好的答案!