5

I'm experimenting with while read syntax and there is a thing I don't understand.

The most basic scenario which reproduces the problem is the following: a bash script a.sh calls another script b.sh and displays the lines echoed by it:

a.sh

#!/bin/bash

while read line; do echo "<<$line>>" done <<< ./b.sh

b.sh

#!/bin/bash

echo "Hello" echo "World"

Running b.sh gives as expected:

Hello
World

On the other hand, when I run a.sh, the output is:

<<Hello World>>

while I expect it to be:

<<Hello>>
<<World>>

What am I doing wrong?

  • 3
    Try putting "" quotes around "`./b.sh`" and see what happens. – jw013 Oct 25 '14 at 00:35
  • You don't need a.sh to be surprised, just run echo \./b.sh``. Then try IFS=' '; echo \./b.sh`` – jimmij Oct 25 '14 at 00:48
  • @jw013: hm, interesting, it works. Doing ./b.sh | while read ... done works too. Would you like writing an answer, explaining why the code in my question doesn't work, while two other alternatives do? – Arseni Mourzenko Oct 25 '14 at 00:50
  • @jimmij: well, the example in my question is simplistic. Actually, what I need to do is to process the output, line by line, instead of simply echoing it. – Arseni Mourzenko Oct 25 '14 at 00:51
  • 4
    @MainMa The main point is that whitespace inside expansions gets lost if you don't double-quote the expansion. You may want to read this: http://mywiki.wooledge.org/Quotes. The ./b.sh | ... example does not use any expansions so doesn't have the quoting problem. I could have sworn there was already a question like this but I can't find one at the moment. – jw013 Oct 25 '14 at 00:56

1 Answers1

5

From the Bash changelog between 4.4-alpha and 4.4-beta:

[...]

This document details the changes between this version, bash-4.4-beta, and the previous version, bash-4.4-alpha.

[...]

z. Bash no longer splits the expansion of here-strings, as the documentation has always said.

That reads a bit ambiguously to me, but whatever changes was committed to the bash sources around that time had the effect that in Bash 4.4, the command

while read line; do
    printf '<<%s>>\n' "$line"
done <<< $( printf '%s\n' hello world )

will produce

<<hello>>
<<world>>

not

<<hello world>>

as in Bash 4.3.

Kusalananda
  • 333,661