Is there a bash command which counts files?
是否有一个bash命令来计算与模式匹配的文件数?
例如,我想得到一个与此模式匹配的目录中所有文件的计数:
这个简单的一行程序应该在任何shell中工作,而不仅仅是bash:
1 | ls -1q log* | wc -l |
ls-1q为每个文件提供一行,即使它们包含空格或换行符等特殊字符。
输出通过管道传输到wc-l,它计算行数。
您可以使用bash安全地执行此操作(即不会被带有空格的文件或名称为
1 2 3 | $ shopt -s nullglob $ logfiles=(*.log) $ echo ${#logfiles[@]} |
如果没有匹配的文件,您需要启用
这里有很多答案,但有些没有考虑到
- 包含空格、换行符或控制字符的文件名
- 以连字符开头的文件名(假设一个名为
-l 的文件) - 隐藏文件,以点开头(如果glob是
*.log ,而不是log* 。 - 与全局匹配的目录(例如,名为
logs 的目录与log* 匹配) - 空目录(即结果为0)
- 非常大的目录(列出所有目录可能会耗尽内存)
这里有一个解决方案可以处理所有这些问题:
1 | ls 2>/dev/null -Ubad1 -- log* | wc -l |
说明:
-U 导致ls 无法对条目进行排序,这意味着它不需要在内存中加载整个目录列表。-b 打印非图形字符的C样式转义,关键是使换行符打印为 。
-a 打印出所有文件,甚至隐藏文件(当globallog* 表示没有隐藏文件时,不严格需要)-d 打印目录而不试图列出目录的内容,这是ls 通常会做的。-1 确保它在一列上(ls在写入管道时自动执行此操作,因此没有严格必要)2>/dev/null 重定向stderr,以便如果有0个日志文件,忽略错误消息。(注意,shopt -s nullglob 会导致ls 列出整个工作目录。)wc -l 在生成目录列表时使用目录列表,因此ls 的输出在任何时间点都不在内存中。-- 文件名与使用-- 的命令分开,以便不被理解为ls 的参数(如果log* 被删除)。
shell会将
1 | ls -Uba1 | grep ^log | wc -l |
最后一个处理非常大的文件目录,而不使用大量内存(尽管它确实使用了子shell)。
对于递归搜索:
1 | find . -type f -name '*.log' | wc -l |
对于非递归搜索,请执行以下操作:
1 | find . -maxdepth 1 -type f -name '*.log' | wc -l |
这个问题被接受的答案是错误的,但我的代表性很低,所以无法对其添加评论。
该问题的正确答案由Mat给出:
1 2 3 | shopt -s nullglob logfiles=(*.log) echo ${#logfiles[@]} |
接受的答案的问题是wc-l计算换行字符的数量,并对它们进行计数,即使它们以'?'的形式打印到终端。在"ls-l"的输出中。这意味着当文件名包含换行符时,接受的回答将失败。我已经测试了建议的命令:
1 | ls -l log* | wc -l |
它错误地报告值2,即使只有1个文件与模式匹配,而模式的名称恰好包含换行符。例如:
1 2 3 | touch log$' 'def ls log* -l | wc -l |
如果您有很多文件,并且不想使用优雅的
1 2 | find -maxdepth 1 -name"log*" -not -name".*" -printf '%i ' | wc -l |
这将找到所有与log*匹配的文件,并且不以
这是一个正确的答案,可以处理任何类型的文件名,因为文件名不会在命令之间传递。
但是,
这是我的单程机票。
1 | file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#) |
您可以使用-r选项查找文件以及递归目录中的文件。
1 2 3 | ls -R | wc -l // to find all the files ls -R | grep php | wc -l // to find the files which contains the word php |
你可以在grep上使用模式
我总是这样做:
ls log* | awk 'END{print NR}'
1 | ls -1 log* | wc -l |
这意味着每行列出一个文件,然后通过管道将其传输到字计数命令,参数切换到计数行。