Bash: count number of lines in previously captured stdout

If you have captured the multi-line output of a previous Bash command in a variable and later need to count the number of lines stored in that variable, you may reach for an apparently easy solution first.  But there are corner cases you may not have covered.

The first syntax gotcha is to make sure you have put quotes around the variable.  But there are still problems when the variable is empty or undefined.

# variable has 3 lines of output
$ mylines=$'a\nb\nc'

# notice that line count is wrong
$ echo $mylines | wc -l
1

# surround variable with quotes to correct
# BUT this still does not solve corner cases!!!
$ echo "$mylines" | wc -l
3

# printf is problematic last line without EOL not counted
$ printf "$mylines" | wc -l
2

# 'wc' incorrectly returns 1 when empty/undefined
$ mylines=""; echo -e "$mylines" | wc -l
$ unset mylines; echo -e "$mylines" | wc -l

# 'sed' also incorrectly returns 1 when empty/undefined
mylines=""; echo -e "$mylines" | awk 'END { print NR }'
unset mylines; echo -e "$mylines" | awk 'END { print NR }'

The proper behavior can be achieved for all these cases by using either:

  • printf paired with grep count (-c)
  • OR echo with no trailing newline (-n) and backslash interpretation (-e), paired with grep count (-c)

Below is printf paired with grep count:

# correct for multiple lines
$ mylines=$'a\nb\nc'; printf "$mylines" | grep -c ""
3

# correct for single line
$ mylines="single line"; printf "$mylines" | grep -c ""
1

# correct for empty line
$ mylines=""; printf "$mylines" | grep -c ""
0

# correct for undefined variable
$ unset mylines; printf "$mylines" | grep -c ""
0

OR echo with ‘ne’ flags paired with grep count:

# correct for multiple lines
$ mylines=$'a\nb\nc'; echo -ne "$mylines" | grep -c ""
3
# correct for single lines
$ mylines="single line"; echo -ne "$mylines" | grep -c ""
1

# correct for empty line
$ mylines=""; echo -ne "$mylines" | grep -c ""
0

# correct for undefined variables
$ unset mylines; echo -ne "$mylines" | grep -c ""
0

REFERENCES

stackexchange Montells, count number of lines output from previous program

grep man page