3 Answers
3

The simple answer is that wc -l <<< "${string_variable}" is a ksh/bash/zsh shortcut for printf "%s\n" "${string_variable}" | wc -l.

There are actually differences in the way <<< and a pipe work: <<< creates a temporary file that is passed as input to the command, whereas | creates a pipe. In bash and pdksh/mksh (but not in ksh93 or zsh), the command on right-hand side of the pipe runs in a subshell. But these differences don't matter in this particular case.

Note that in terms of counting lines, this assumes that the variable is not empty and does not end with a newline. Not ending with a newline is the case when the variable is the result of a command substitution, so you'll get the right result in most cases, but you'll get 1 for the empty string.

There are two differences between var=$(somecommand); wc -l <<<"$var" and somecommand | wc -l: using a command substitution and a temporary variable strips away blank lines at the end, forgets whether the last line of output ended in a newline or not (it always does if the command outputs a valid nonempty text file), and overcounts by one if the output is empty. If you want to both preserve the result and count lines, you can do it by appending some known text and stripping it off at the end:

@Inian Keeping wc -l is exactly equivalent to the original: <<<$foo adds a newline to the value of $foo (even if $foo was empty). I explain in my answer why this may not have been what was wanted, but it's what was asked.
– GillesNov 20 at 7:20

Note that some of the GNU tools, especially, GNU grep does not respect POSIXLY_CORRECT=1 option to run the POSIX version of the tool. In grep the only behavior affected by setting the variable will be the difference in processing of the order of the command line flags. From the documentation (GNU grep manual), it seems that

POSIXLY_CORRECT

If set, grep behaves as POSIX requires; otherwise, grep behaves more like other GNU programs. POSIX requires that options that follow file names must be treated as file names; by default, such options are permuted to the front of the operand list and are treated as options.

@MichaelHomer: From what I've observed, wc -l needs a proper newline delimited stream (having a trailing '\n` at the end to count properly). One cannot use a simple FIFO to use with printf, e.g. printf '%s' "${string_variable}" | wc -l might not work as expected but <<< would because of the trailing \n appended by the herestring
– InianNov 20 at 7:14

1

That was what printf '%s\n' was doing, before you took it out...
– Michael HomerNov 20 at 7:18