如何计算shell脚本中变量的行数

时间:2015-09-22 21:21:54

标签: shell unix ksh

在这里遇到麻烦。我想将ls命令的输出捕获到变量中。然后使用该变量并计算其中的行数。我尝试了一些变化

这样可行,但如果没有.txt文件,则表示计数为1:

testVar=`ls -1 *.txt`
count=`wc -l <<< $testVar`
echo '$count'

这适用于没有.txt文件的情况,但是当有.txt文件时,计数会短1:

testVar=`ls -1 *.txt`
count=`printf '$testVar' | wc -l`
echo '$count'

此变体还表示存在NO .txt文件时计数为1:

testVar=`ls -1 *.txt`
count=`echo '$testVar' | wc -l`
echo '$count'

编辑:我应该提到这是korn shell。

4 个答案:

答案 0 :(得分:2)

正确的方法是使用数组。

# Use ~(N) so that if the match fails, the array is empty instead
# of containing the pattern itself as the single entry.
testVar=( ~(N)*.txt )
count=${#testVar[@]}

答案 1 :(得分:2)

这个小问题实际上包括三个标准shell陷阱(bash和korn shell)的结果:

  1. 如果这些字符串(<<<...)不以新行结尾,则会向其添加换行符。这使得无法使用here-string向命令发送完全空的输入。

  2. 从命令替换(cmd或最好$(cmd))中使用的命令的输出中删除所有尾随换行符。所以你无法知道输出结尾有多少空​​行。

  3. (不是真的是一个shell getcha,但它出现了很多)。 wc -l计算换行符的数量,而不是行数。所以最后一行&#34;&#34;如果没有以换行符终止,则不计算在内。 (不以换行符结尾的非空文件不是符合Posix的文本文件。所以这样奇怪的结果并不出乎意料。)

  4. 所以,当你这样做时:

    var=$(cmd)
    utility <<<"$var"
    

    第一行中的命令替换删除所有尾随换行符,然后第二行中的here-string扩展将恰好放回一个尾随换行符。这会将空输出转换为单个空行,否则会从输出的末尾删除空白行。

    所以utilitywc -l,那么除非输出为空,否则你将获得正确的计数,在这种情况下,它将是1而不是0。

    另一方面,用

    var=$(cmd)
    printf %s "$cmd" | utility
    

    如前所述,通过命令替换删除尾随换行符,因此printf使最后一行(如果有)未终止。现在,如果utilitywc -l,如果输出为空,则最终为0,但对于非空文件,计数将不包括输出的最后一行。

    一种可能的与shell无关的解决方法是使用第二个选项,但使用grep ''作为过滤器:

    var=$(cmd)
    printf %s "${var}" | grep '' | utility
    

    空图案&#39;&#39;将匹配每一行,grep总是终止每一行输出。 (当然,这仍然不会在输出结束时计算空白行。)

    说了这么多,尝试解析ls的输出总是一个坏主意,甚至只是计算文件数。 (例如,文件名可能包含换行符。)因此,最好使用glob扩展结合一些特定于shell的方法来计算glob扩展中的对象数(以及其他一些特定于shell的检测方法)当没有文件与glob匹配时。)

答案 2 :(得分:0)

你也可以这样使用:

#!/bin/bash

testVar=`ls -1 *.txt`

if [ -z "$testVar" ]; then
        # Empty
        count=0
else
        # Not Empty
        count=`wc -l <<< "$testVar"`
fi

echo "Count : $count"

答案 3 :(得分:0)

我打算建议这个,这是我在bash中使用的一个结构:

f=($(</path/to/file))
echo ${#f[@]}

要处理多个文件,您只需添加文件。

f=($(</path/to/file))
f=+($(</path/to/otherfile))

f=($(</path/to/file) $(</path/to/otherfile))

要处理大量文件,您可以循环:

f=()
for file in *.txt; do
    f+=($(<$file))
done

然后我看到了chepner的反应,我收集的反应比我的反应更为明显。

注意:循环优于parsing ls