是否有一个bash命令来计算匹配模式的文件数量?
例如,我想获取目录中所有文件的计数,这些文件都符合这个模式:log*
是否有一个bash命令来计算匹配模式的文件数量?
例如,我想获取目录中所有文件的计数,这些文件都符合这个模式:log*
当前回答
我已经对这个答案进行了很多思考,特别是考虑到不要解析这些东西。起初,我尝试过
<WARNING! DID NOT WORK>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</WARNING! DID NOT WORK>
如果只有像这样的文件名,这是可行的
touch $'w\nlf.aa'
但如果我创建这样的文件名就失败了
touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'
我终于想到了下面这些。注意,我试图获得目录中所有文件的计数(不包括任何子目录)。我认为它,连同@Mat和@Dan_Yard的答案,以及至少有@mogsie设定的大部分要求(我不确定内存)。我认为@mogsie的答案是正确的,但我总是尽量避免解析ls,除非是非常特定的情况。
awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'
更可读的:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -print0) | \
awk '{sum+=$1}END{print sum}'
这是专门为文件执行查找,用空字符分隔输出(以避免空格和换行问题),然后计算空字符的数量。文件的数量将比空字符的数量少一个,因为在最后会有一个空字符。
要回答OP的问题,有两种情况需要考虑
1)非递归搜索:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
2)递归搜索。请注意,name参数中的内容可能需要针对略有不同的行为(隐藏文件等)进行更改。
awk -F"\0" '{print NF-1}' < \
<(find . -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
如果有人想评论这些答案与我在这个答案中提到的答案相比如何,请评论。
注意,我是在得到这个答案的同时进行这个思考过程的。
其他回答
这个问题的公认答案是错误的,但我有低代表,所以不能添加评论。
这个问题的正确答案由Mat给出:
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
接受的答案的问题是wc -l计算换行符的数量,即使它们打印到终端,也将它们计算为'?'ls -l'的输出。这意味着当文件名包含换行符时,接受的答案失败。我已经测试了建议的命令:
ls -l log* | wc -l
而且即使只有一个文件名恰好包含换行符的文件与模式匹配,它也会错误地报告值2。例如:
touch log$'\n'def
ls log* -l | wc -l
这可以用标准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}
))
ls -1 log* | wc -l
这意味着每行列出一个文件,然后将其输送到单词计数命令,参数切换到计数行。
这个简单的一行代码可以在任何shell中工作,而不仅仅是bash:
ls -1q log* | wc -l
Ls -1q将为每个文件提供一行,即使它们包含空格或换行符等特殊字符。
输出被输送到wc -l,它计算行数。
下面是一个可以在脚本中使用的通用Bash函数。
# @see https://stackoverflow.com/a/11307382/430062
function countFiles {
shopt -s nullglob
logfiles=($1)
echo ${#logfiles[@]}
}
FILES_COUNT=$(countFiles "$file-*")