是否有统计文件的bash命令?
是否有一个bash命令来统计与模式匹配的文件数是否有统计文件的bash命令?,bash,Bash,是否有一个bash命令来统计与模式匹配的文件数 例如,我想获取目录中与此模式匹配的所有文件的计数:log*对于递归搜索: 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 这个简单的一行程序应该适用于任何she
例如,我想获取目录中与此模式匹配的所有文件的计数:
log*
对于递归搜索:
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
这个简单的一行程序应该适用于任何shell,而不仅仅是bash:
ls -1q log* | wc -l
ls-1q将为每个文件提供一行,即使它们包含空格或特殊字符,如换行符
find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l
输出通过管道传输到wc-l,wc-l统计行数。使用bash可以安全地执行此操作(即不会被带有空格或名称中带有\n
的文件所干扰):
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
您需要启用,以便在没有匹配的文件时,不会在$logfiles
中获取文本*.log
。(有关如何安全重置的示例,请参见。)
这意味着每行列出一个文件,然后通过管道将其传输到word count命令,并将参数切换为计数行。如果您有很多文件,并且不想使用优雅的
shopt-s nullglob
和bash数组解决方案,则可以使用find等,只要不打印文件名(可能包含新行)
这将查找所有与log*匹配且不以*
开头的文件-“not name.*”是redunant,但需要注意的是,“ls”的默认值是不显示点文件,而“find”的默认值是包含它们
这是一个正确的答案,可以处理任何类型的文件名,因为文件名永远不会在命令之间传递
但是,
shopt nullglob
答案是最好的答案 这个问题的公认答案是错误的,但我的代表性较低,因此无法添加评论
Mat给出了该问题的正确答案:
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
接受答案的问题是wc-l统计换行符的数量,即使它们在“ls-l”的输出中以“?”的形式打印到终端,也会统计换行符的数量。这意味着当文件名包含换行符时,接受的答案将失败。我已经测试了建议的命令:
ls -l log* | wc -l
即使只有1个文件与模式匹配,且其名称恰好包含换行符,它也会错误地报告值2。例如:
touch log$'\n'def
ls log* -l | wc -l
这里有很多答案,但有些没有考虑
- 包含空格、换行符或控制字符的文件名
- 以连字符开头的文件名(想象一个名为
的文件)-l
- 隐藏文件,以点开头(如果glob是
而不是*.log
log*
- 与glob匹配的目录(例如,与
匹配的名为log*
的目录)logs
- 空目录(即结果为0)
- 超大目录(列出所有目录可能会耗尽内存)
ls 2>/dev/null -Ubad1 -- log* | wc -l
说明:
导致-U
不对条目进行排序,这意味着它不需要在内存中加载整个目录列表ls
为非图形字符打印C样式转义符,这将导致换行符打印为-b
\n
打印出所有文件,甚至是隐藏的文件(当glob-a
表示没有隐藏的文件时,不需要)log*
打印出目录而不尝试列出目录的内容,这是-d
通常会做的事情ls
确保它位于一列上(ls在写入管道时会自动执行此操作,因此严格来说不需要)-1
重定向stderr,以便如果有0个日志文件,忽略错误消息。(请注意,2>/dev/null
将导致shopt-s nullglob
列出整个工作目录。)ls
在生成目录列表时使用目录列表,因此wc-l
的输出在任何时间点都不在内存中ls
使用-->
将文件名与命令分开,以免被理解为-->
的参数(如果删除了ls
)log*
log*
扩展到完整的文件列表,如果文件太多,可能会耗尽内存,因此通过grep运行它会更好:
ls -Uba1 | grep ^log | wc -l
最后一个处理非常大的文件目录而不使用大量内存(尽管它确实使用子shell)。不再需要
-d
,因为它只列出当前目录的内容。这是我的一行代码
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
您可以使用-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上使用模式,以下是我经常做的: ls log*| awk'结束{打印编号}'
您可以使用shell函数轻松定义此类命令。此方法不需要任何外部程序,也不会生成任何子进程。它不会尝试危险的
ls
解析,并处理“特殊”字符(空格、换行符、反斜杠等)很好。它只依赖于shell提供的文件名扩展机制。它至少与sh、bash和zsh兼容
下一行定义了一个名为count
的函数,它打印调用它的参数数
count() { echo $#; }
只需使用所需的模式调用它:
count log*
为使全局模式不匹配时的结果正确,必须在扩展发生时设置shell选项nullglob
(或failglob
——这是zsh上的默认行为)。可以如下设置
count log*
shopt -s nullglob # for sh / bash
setopt nullglob # for zsh
( shopt -s nullglob ; shopt -u failglob ; count log* )
# 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)
find "$FIND_OPTIONS" -exec count {} \+ # count results of a search
<WARNING! DID NOT WORK>
</WARNING! DID NOT WORK>
ls | wc -l
ls | grep log | wc -l
ls -1q some_pattern | wc -l
shopt -s nullglob; files=(some_pattern); echo ${#files[@]};