如何计算 shell 脚本中变量的行数
how to count the number of lines in a variable in a shell script
这里有点问题。我想将 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'
此变体还表示当不存在 .txt 文件时计数为 1:
testVar=`ls -1 *.txt`
count=`echo '$testVar' | wc -l`
echo '$count'
编辑:我应该提到这是 korn shell。
正确的做法是使用数组。
# 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[@]}
你也可以这样使用:
#!/bin/bash
testVar=`ls -1 *.txt`
if [ -z "$testVar" ]; then
# Empty
count=0
else
# Not Empty
count=`wc -l <<< "$testVar"`
fi
echo "Count : $count"
我打算建议这个,这是我在 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。
这个小问题实际上包括三个标准 shell 陷阱(bash 和 korn shell)的结果:
Here-strings (<<<...
) 如果不以换行符结尾则添加换行符。这使得无法将完全空的输入发送到带有此处字符串的命令。
所有尾随的换行符都从命令替换中使用的命令的输出中删除(cmd
或最好是 $(cmd)
)。所以你无法知道输出末尾有多少空行。
(不是真正的 shell 陷阱,但经常出现)。 wc -l
计算 换行符 的数量,而不是行数。所以如果最后一个 "line" 没有以换行符终止,则不计算在内。 (不以换行符结尾的非空文件不是符合 Posix 的文本文件。所以像这样的奇怪结果并不意外。)
所以,当你这样做时:
var=$(cmd)
utility <<<"$var"
第一行中的命令替换删除了所有尾随换行符,然后第二行中的此处字符串扩展正好放回了一个尾随换行符。将空输出转换为单个空行,否则从输出末尾删除空行。
所以 utility
是 wc -l
,那么你将得到正确的计数,除非输出为空,在这种情况下它将是 1 而不是 0。
另一方面,
var=$(cmd)
printf %s "$cmd" | utility
像以前一样,命令替换删除了尾随的换行符,因此 printf
留下最后一行(如果有的话)未终止。现在,如果 utility
是 wc -l
,如果输出为空,您将以 0 结束,但对于非空文件,计数将不包括输出的最后一行。
一种可能的 shell 独立解决方法是使用第二个选项,但使用 grep ''
作为过滤器:
var=$(cmd)
printf %s "${var}" | grep '' | utility
空模式 '' 将匹配每一行,并且 grep
总是终止每一行输出。 (当然,这仍然不会计算输出末尾的空行。)
话虽如此,尝试解析 ls
的输出总是一个坏主意,即使只是计算文件的数量也是如此。 (例如,文件名可能包含换行符。)因此,最好结合使用 glob 扩展和一些 shell-specific 方法来计算 glob 扩展中的对象数量(以及其他一些 shell-当没有文件与 glob 匹配时检测的特定方法。
这里有点问题。我想将 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'
此变体还表示当不存在 .txt 文件时计数为 1:
testVar=`ls -1 *.txt`
count=`echo '$testVar' | wc -l`
echo '$count'
编辑:我应该提到这是 korn shell。
正确的做法是使用数组。
# 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[@]}
你也可以这样使用:
#!/bin/bash
testVar=`ls -1 *.txt`
if [ -z "$testVar" ]; then
# Empty
count=0
else
# Not Empty
count=`wc -l <<< "$testVar"`
fi
echo "Count : $count"
我打算建议这个,这是我在 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。
这个小问题实际上包括三个标准 shell 陷阱(bash 和 korn shell)的结果:
Here-strings (
<<<...
) 如果不以换行符结尾则添加换行符。这使得无法将完全空的输入发送到带有此处字符串的命令。所有尾随的换行符都从命令替换中使用的命令的输出中删除(
cmd
或最好是$(cmd)
)。所以你无法知道输出末尾有多少空行。(不是真正的 shell 陷阱,但经常出现)。
wc -l
计算 换行符 的数量,而不是行数。所以如果最后一个 "line" 没有以换行符终止,则不计算在内。 (不以换行符结尾的非空文件不是符合 Posix 的文本文件。所以像这样的奇怪结果并不意外。)
所以,当你这样做时:
var=$(cmd)
utility <<<"$var"
第一行中的命令替换删除了所有尾随换行符,然后第二行中的此处字符串扩展正好放回了一个尾随换行符。将空输出转换为单个空行,否则从输出末尾删除空行。
所以 utility
是 wc -l
,那么你将得到正确的计数,除非输出为空,在这种情况下它将是 1 而不是 0。
另一方面,
var=$(cmd)
printf %s "$cmd" | utility
像以前一样,命令替换删除了尾随的换行符,因此 printf
留下最后一行(如果有的话)未终止。现在,如果 utility
是 wc -l
,如果输出为空,您将以 0 结束,但对于非空文件,计数将不包括输出的最后一行。
一种可能的 shell 独立解决方法是使用第二个选项,但使用 grep ''
作为过滤器:
var=$(cmd)
printf %s "${var}" | grep '' | utility
空模式 '' 将匹配每一行,并且 grep
总是终止每一行输出。 (当然,这仍然不会计算输出末尾的空行。)
话虽如此,尝试解析 ls
的输出总是一个坏主意,即使只是计算文件的数量也是如此。 (例如,文件名可能包含换行符。)因此,最好结合使用 glob 扩展和一些 shell-specific 方法来计算 glob 扩展中的对象数量(以及其他一些 shell-当没有文件与 glob 匹配时检测的特定方法。