在 bash 中,如何计算变量中的行数?

我有一个变量,它有一个字符串存储在里面,需要检查它是否有行:

var=`ls "$sdir" | grep "$input"`

伪代码:

while [ ! $var's number of lines -eq 1 ]
do something

这是我的想法,关于如何检查它。echo $var | wc -l不工作-它总是说 1,即使它有 3

echo -e不能正常工作。

109445 次浏览

Quotes matter.

echo "$var" | wc -l

You can substitute the "wc -l" with "wc -w" to rather count the number of words instead of lines. This will not count any new lines and can be used to test if your original results are empty before you continue.

Another way using here strings in bash:

wc -l <<< "$var"

As mentioned in this comment, an empty $var will result in 1 line instead of 0 lines because here strings add a newline character in this case (explanation).

The accepted answer and other answers posted here do not work in case of an empty variable (undefined or empty string).

This works:

echo -n "$VARIABLE" | grep -c '^'

For example:

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

The top voted answers fail if no results were returned by a grep.

Homer Simpson
Marge Simpson
Bart Simpson
Lisa Simpson
Ned Flanders
Rod Flanders
Todd Flanders
Moe Szyslak

This is the wrong way to do it:

wiggums=$(grep -iF "Wiggum" characters.txt);
num_wiggums=$(echo "$wiggums" | wc -l);
echo "There are ${num_wiggums} here!";

There will tell us, there is 1 Wiggum in the list, even if there aren't any.

Instead, you need to do one extra check to see if the variable is empty (-z, as in "is zero"). If grep didn't return anything, the variable will be empty.

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";

No one has mentioned parameter expansion, so here are a couple of ways using pure bash.

Method 1

Remove non-newline characters, then get string length + 1. Quotes are important.

 var="${var//[!$'\n']/}"
echo $((${#var} + 1))

Method 2

Convert to array, then get array length. For this to work, don't use quotes.

 set -f # disable glob (wildcard) expansion
IFS=$'\n' # let's make sure we split on newline chars
var=(${var})
echo ${#var[@]}

A simpler version of @Julian's answer, that works for all strings, with or without trailing \n (it does count a file containing just a single trailing \n as empty):

printf "%s" "$a" | grep -c "^"

  • Returns zero: unset variable, empty string, string containing bare newline
  • Returns 1: any non-empty line, with or without trailing newline
  • etc

Output:

# 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

Another method to count number of lines in a variable - assuming you did check it was successfully filled or it is not empty, for that just check $? after var subshell result affectation - :

readarray -t tab <<<"${var}"
echo ${#tab[@]}

readarray|mapfile is bash internal command which converts input file, or here string in this case, to array based on newlines.

-t flag prevents storing newlines at end of array's cells, useful for later use of stored values

Advantages of this method are :

  • no external command (wc, grep, ...)
  • no subshell (pipe)
  • no IFS issues (restore after modification, tricky to use with command-limited scope on internal commands, ...)

To avoid filename in "wc -l" command:

lines=$(< "$filename" wc -l)
echo "$lines"