如何用 awk 替换 sed 和 wc? (计算目录中的名称)

如何用 awk 替换 sed 和 wc? (计算目录中的名称)

我想计算文件夹内的元素数量。我想到了

function lsc { /bin/ls -l $1 | sed 1d | wc -l }

但后来我想起awk人们是如何减少这些管道,摆脱多余的greps 和seds 的。那么,你会怎么做呢awk

答案1

不需要lssedwcawk

如果您只是想计算模式扩展为多少个名称,那么您可以使用

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

相关内容