我想计算文件夹内的元素数量。我想到了
function lsc { /bin/ls -l $1 | sed 1d | wc -l }
但后来我想起awk
人们是如何减少这些管道,摆脱多余的grep
s 和sed
s 的。那么,你会怎么做呢awk
?
答案1
不需要ls
、sed
、wc
或awk
。
如果您只是想计算模式扩展为多少个名称,那么您可以使用
set -- *
echo "$#"
该set
命令将位置参数( 、 等)设置$1
为与模式$2
匹配的名称*
。这会自动将特殊变量设置$#
为设置的位置参数的数量,即与给定模式匹配的名称的数量。
在bash
具有命名数组的 shell 中,您可以使用
names=(*)
echo "${#names[@]}"
其工作原理类似,但将数组的元素设置names
为模式扩展所产生的名称*
。变量扩展${#names[@]}
将是数组中元素的数量names
。
这样做的一个问题是,如果模式不匹配任何内容,它将保持未展开状态,因此计数为 1(即使目录为空)。要在 shell 中修复此问题bash
,请nullglob
使用 来设置 shell 选项shopt -s nullglob
。通过设置此 shell 选项,不匹配任何内容的模式将被完全删除。
在 中bash
,如果您还想计算隐藏名称的数量,请dotglob
使用 来设置 shell 选项shopt -s dotglob
。
你的函数可能看起来像这样bash
:
lsc () (
shopt -s nullglob
set -- "$1"/*
echo "$#"
)
( ... )
请注意在函数体中使用以避免nullglob
在调用 shell 中进行设置。
或者,对于/bin/sh
:
lsc () {
set -- "$1"/*
if [ -e "$1" ] || [ -L "$1" ]; then
echo "$#"
else
echo 0
fi
}
这里的语句if
确保第一个位置参数是实际文件的名称,而不是未扩展的模式(由于不匹配任何内容)。 (-e
“存在”)必须为真,我们才能信任 中的数字$#
。如果不正确,那么我们还会检查该名称是否引用测试的符号链接-L
。如果这是真的,我们就知道该模式扩展为的第一个东西是“死”符号链接(指向不存在的文件的符号链接),并且我们相信$#
它是正确的。如果两个测试都失败,我们就知道我们没有匹配任何内容,因此输出0
。
答案2
首先,您的单行函数定义不正确。该关键字的存在表明您可能使用 Bash,这就是man bash 中function
的内容:Shell Function Definitions
function name [()] compound-command [redirection]
而复合命令定义为:
{ list; }
所以应该是:
function lsc { /bin/ls -l $1 | sed 1d | wc -l; }
但即使它在技术上是正确的,它也不会很好地工作,请参阅
为什么不是解析ls
(以及该怎么做)?。
您可以使用 awk 打印给定目录中的多个文件和目录,如下所示:
awk 'END {print ARGC - 1}' *
但请注意,如果 shell 扩展的参数中至少有一个*
是目录,则 awk 会抱怨:
$ awk 'END {print ARGC - 1}' *
awk: warning: command line argument `dir1' is a directory: skipped
但无论如何,结果仍然很好,你可以将错误重定向到/dev/null:
awk 'END {print ARGC - 1}' * 2>/dev/null