是否有一个bash命令来计算匹配模式的文件数量?
例如,我想获取目录中所有文件的计数,这些文件都符合这个模式:log*
是否有一个bash命令来计算匹配模式的文件数量?
例如,我想获取目录中所有文件的计数,这些文件都符合这个模式:log*
当前回答
ls -1 log* | wc -l
这意味着每行列出一个文件,然后将其输送到单词计数命令,参数切换到计数行。
其他回答
一个重要的评论
(没有足够的声誉来评论)
这是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。
您可以使用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
对于递归搜索:
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
下面是一个可以在脚本中使用的通用Bash函数。
# @see https://stackoverflow.com/a/11307382/430062
function countFiles {
shopt -s nullglob
logfiles=($1)
echo ${#logfiles[@]}
}
FILES_COUNT=$(countFiles "$file-*")
这可以用标准POSIX shell语法完成。
下面是一个简单的count_entries函数:
#!/usr/bin/env sh
count_entries()
{
# Emulating Bash nullglob
# If argument 1 is not an existing entry
if [ ! -e "$1" ]
# argument is a returned pattern
# then shift it out
then shift
fi
echo $#
}
对于紧凑的定义:
count_entries(){ [ ! -e "$1" ]&&shift;echo $#;}
特色POSIX兼容的文件计数器类型:
#!/usr/bin/env sh
count_files()
# Count the file arguments matching the file operator
# Synopsys:
# count_files operator FILE [...]
# Arguments:
# $1: The file operator
# Allowed values:
# -a FILE True if file exists.
# -b FILE True if file is block special.
# -c FILE True if file is character special.
# -d FILE True if file is a directory.
# -e FILE True if file exists.
# -f FILE True if file exists and is a regular file.
# -g FILE True if file is set-group-id.
# -h FILE True if file is a symbolic link.
# -L FILE True if file is a symbolic link.
# -k FILE True if file has its `sticky' bit set.
# -p FILE True if file is a named pipe.
# -r FILE True if file is readable by you.
# -s FILE True if file exists and is not empty.
# -S FILE True if file is a socket.
# -t FD True if FD is opened on a terminal.
# -u FILE True if the file is set-user-id.
# -w FILE True if the file is writable by you.
# -x FILE True if the file is executable by you.
# -O FILE True if the file is effectively owned by you.
# -G FILE True if the file is effectively owned by your group.
# -N FILE True if the file has been modified since it was last read.
# $@: The files arguments
# Output:
# The number of matching files
# Return:
# 1: Unknown file operator
{
operator=$1
shift
case $operator in
-[abcdefghLkprsStuwxOGN])
for arg; do
# If file is not of required type
if ! test "$operator" "$arg"; then
# Shift it out
shift
fi
done
echo $#
;;
*)
printf 'Invalid file operator: %s\n' "$operator" >&2
return 1
;;
esac
}
count_files "$@"
示例用法:
count_files -f log*.txt
count_files -d datadir*
计数没有循环的非目录条目:
#!/bin/sh
# Creates strings of as many dots as expanded arguments
# dotted string for entries matching star pattern
star=$(printf '%.0s.' ./*)
# dotted string for entries matching star slash pattern (directories)
star_dir=$(printf '%.0s.' ./*/)
# dotted string for entries matching dot star pattern
dot_star=$(printf '%.0s.' ./.*)
# dotted string for entries matching dot star slash pattern (directories)
dot_star_dir=$(printf '%.0s.' ./.*/)
# Print pattern matches count excluding directories matches
printf 'Files count: %d\n' $((
${#star} - ${#star_dir} +
${#dot_star} - ${#dot_star_dir}
))