krack krackerz
krack krackerz

Reputation: 1529

In bash, how do I count the number of lines in a variable?

I have a variable which has a string stored in it and need to check if it has lines in it:

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

pseudo-code:

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

That's my idea on how to check it. echo $var | wc -l doesn't work - it always says 1, even though it has 3.

echo -e doesn't work as well.

Upvotes: 133

Views: 133448

Answers (9)

user3503711
user3503711

Reputation: 2046

To avoid filename in wc -l command:

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

Upvotes: 4

haqk
haqk

Reputation: 177

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[@]}

Upvotes: 17

adrenochrome
adrenochrome

Reputation: 61

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, ...)

Upvotes: 6

Stilez
Stilez

Reputation: 570

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

Upvotes: 14

speakr
speakr

Reputation: 4209

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).

Upvotes: 34

Jonathan Matthews
Jonathan Matthews

Reputation: 135

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

Upvotes: 3

Julian
Julian

Reputation: 4780

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

Upvotes: 138

Christopher Brunsdon
Christopher Brunsdon

Reputation: 496

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.

Upvotes: 9

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798456

Quotes matter.

echo "$var" | wc -l

Upvotes: 148

Related Questions