【发布时间】:2011-09-12 23:14:31
【问题描述】:
我有一个变量,其中存储了一个字符串,需要检查它是否有行:
var=`ls "$sdir" | grep "$input"`
伪代码:
while [ ! $var's number of lines -eq 1 ]
do something
这是我关于如何检查它的想法。 echo $var | wc -l 不起作用 - 它总是显示 1,即使它有 3。
echo -e 也不行。
【问题讨论】:
我有一个变量,其中存储了一个字符串,需要检查它是否有行:
var=`ls "$sdir" | grep "$input"`
伪代码:
while [ ! $var's number of lines -eq 1 ]
do something
这是我关于如何检查它的想法。 echo $var | wc -l 不起作用 - 它总是显示 1,即使它有 3。
echo -e 也不行。
【问题讨论】:
为了避免“wc -l”命令中的文件名:
lines=$(< "$filename" wc -l)
echo "$lines"
【讨论】:
没有人提到参数扩展,所以这里有两种使用纯 bash 的方法。
方法一
去掉非换行符,然后得到字符串长度+1。引号很重要。
var="${var//[!$'\n']/}"
echo $((${#var} + 1))
方法二
转换为数组,然后得到数组长度。 为此,请不要使用引号。
set -f # disable glob (wildcard) expansion
IFS=$'\n' # let's make sure we split on newline chars
var=(${var})
echo ${#var[@]}
【讨论】:
IFS。所以设置IFS=$'\n' 以确保在将变量扩展为数组时将其拆分为新行:IFS=$'\n'; var=(${var})
set -f 以避免不必要的全局扩展。尝试在var=$'*\n.*'上使用方法2。
wc -l 的自动奖励
另一种计算变量行数的方法 - 假设您确实检查了它是否已成功填充或它不为空,为此只需检查 $?在 var 子外壳结果做作之后 - :
readarray -t tab <<<"${var}"
echo ${#tab[@]}
readarray|mapfile 是 bash 内部命令,它将输入文件或 这里的字符串 在这种情况下转换为基于换行符的数组。
-t 标志防止在数组的单元格末尾存储换行符,对以后使用存储的值很有用
这种方法的优点是:
【讨论】:
@Julian 答案的更简单版本,适用于所有字符串,无论是否有尾随 \n(它确实将仅包含单个尾随 \n 的文件视为空):
printf "%s" "$a" | grep -c "^"
输出:
# a=
# printf "%s" "$a" | grep -c "^"
0
# a=""
# printf "%s" "$a" | grep -c "^"
0
# a="$(printf "")"
# printf "%s" "$a" | grep -c "^"
0
# a="$(printf "\n")"
# printf "%s" "$a" | grep -c "^"
0
# a="$(printf " \n")"
# printf "%s" "$a" | grep -c "^"
1
# a="$(printf " ")"
# printf "%s" "$a" | grep -c "^"
1
# a="aaa"
# printf "%s" "$a" | grep -c "^"
1
# a="$(printf "%s" "aaa")"
# printf "%s" "$a" | grep -c "^"
1
# a="$(printf "%s\n" "aaa")"
# printf "%s" "$a" | grep -c "^"
1
# a="$(printf "%s\n%s" "aaa" "bbb")"
# printf "%s" "$a" | grep -c "^"
2
# a="$(printf "%s\n%s\n" "aaa" "bbb")"
# printf "%s" "$a" | grep -c "^"
2
【讨论】:
echo(例如echo -n)不是标准的,并且可能在不同的实现上给出不同的结果。而printf 默认做我们想要的。作为奖励,使用printf 可以为您节省一个进程,因为它是一个内置的shell。 (建议:printf "$a" | wc -l更简洁,避免不必要的使用grep)
printf .... | wc -l 只会删除一个额外的行(换行符),以便在 空行 的情况下,结果将是 0。正确的。但是如果我们传递 2 行,结果将是 1,其中传递给 printf ... | grep "^" 的相同变量将正确返回 2。此外,直接使用 printf "$a" 是非常危险的,因为如果字符串不小心会导致静默错误包含%s、%d 等字符...如果字符串以破折号开头,则相同。相反,printf 中的 2 参数会自动转义
在 bash 中使用 here strings 的另一种方式:
wc -l <<< "$var"
如this comment 中所述,空的$var 将产生1 行而不是0 行,因为这里的字符串 在这种情况下添加了换行符(explanation)。
【讨论】:
wc -l <<<"$(echo "$var")"(是的,每个符号都是必要的)
$var的内容是什么?
var 包含一行:您没有将\n 解释为任何内容。将多行放入您的 var 中,它将起作用,例如var="foo<ENTER>bar<ENTER>baz"<ENTER>.
xxd <<< '' 创建这个 hexdump 00000000: 0a。因此,<<< (Here Strings) 为任何内容添加换行符。
如果 grep 未返回任何结果,则投票最多的答案将失败。
Homer Simpson
Marge Simpson
Bart Simpson
Lisa Simpson
Ned Flanders
Rod Flanders
Todd Flanders
Moe Szyslak
wiggums=$(grep -iF "Wiggum" characters.txt);
num_wiggums=$(echo "$wiggums" | wc -l);
echo "There are ${num_wiggums} here!";
会告诉我们,列表中有1Wiggum,即使没有。
相反,您需要额外检查变量是否为空(-z,如“为零”)。如果 grep 没有返回任何内容,则该变量将为空。
matches=$(grep -iF "VanHouten" characters.txt);
if [ -z "$matches" ]; then
num_matches=0;
else
num_matches=$(echo "$matches" | wc -l);
fi
echo "There are ${num_matches} VanHoutens on the list";
【讨论】:
此处发布的已接受答案和其他答案在空变量(未定义或空字符串)的情况下不起作用。
这行得通:
echo -n "$VARIABLE" | grep -c '^'
例如:
ZERO=
ONE="just one line"
TWO="first
> second"
echo -n "$ZERO" | grep -c '^'
0
echo -n "$ONE" | grep -c '^'
1
echo -n "$TWO" | grep -c '^'
2
【讨论】:
WHITESPACE_ONE=' ' 仍然有效,正确报告了一行。
printf 而不是echo -n 来简化。我已将此添加为替代答案,以包含测试结果。见下文。
您可以用“wc -w”代替“wc -l”来计算字数而不是行数。这不会计算任何新行,可用于在您继续之前测试您的原始结果是否为空。
【讨论】:
wc -lsolutions即使输入变量为空也会输出1,所以wc -w会更好用。
行情很重要。
echo "$var" | wc -l
【讨论】:
if [ -z "$var" ]; then printf '%s\n' '0'; else printf '%s\n' "${var%$'\n'}" | wc -l; fi。尝试使用 var=(无行)、var='foo' 和 var=$'foo\n'(在 *nix 意义上都是一行)。
LINE_COUNT=$(wc -l <<< "${var}")
echo -n 只会将计数减一。 @lucifurious echo $(wc -l <<< "${NONEXISTENTVAR}") 仍然给出 1,而不是 0