53

How can I read from variable with while read line?

For example:

the_list=$(..code..)

while read line
do
        echo $line

done < $the_list

using the code above gives me error:

./copy.sh: line 25: $the_list: ambiguous redirect
doubleDown
  • 8,048
  • 1
  • 32
  • 48
Crazy_Bash
  • 1,755
  • 10
  • 26
  • 38

4 Answers4

82

You can write:

while IFS= read -r line
do
    echo "$line"
done <<< "$the_list"

See §3.6.7 "Here Strings" in the Bash Reference Manual.

(I've also taken the liberty of adding some double-quotes, and adding -r and IFS= to read, to avoid too much mucking around with the contents of your variables.)

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • 2
    Does `IFS=` set the IFS to null character? Why do you need it in this case? – doubleDown Oct 29 '12 at 14:09
  • 6
    @doubleDown: `IFS=` sets `$IFS` to the empty string (so it doesn't contain any characters at all). In this case, since there's only one field, its only effect is to prevent the removal of leading IFS-characters from the start of the line. (To see what I mean, compare `read foo <<< ' bar' ; echo "$foo"` with `IFS= read foo <<< ' bar' ; echo "$foo"`.) – ruakh Oct 29 '12 at 14:25
31

If you do not use the variable for anything else, you can even do without it:

while read line ; do
    echo $line
done < <( ... code ... )
choroba
  • 231,213
  • 25
  • 204
  • 289
27

You can just use

your_code | while read line;
do
    echo $line
done

if you don't mind the while loop executing in a subshell (any variables you modify won't be visible in the parent after the done).

Useless
  • 64,155
  • 6
  • 88
  • 132
  • This is an old reply. I am interested in the "...(any variables you modify won't be visible in the parent after the done)." part of the statement. How will they be then _visible_? The following example `echo "${NAMES/,/$'\n'}" |while read -r NAME ;do TMP=${NAME#*_} ;TMP2=${TMP%_*_*_*_*_*} ;OUTPUT+=${TMP2/$'\n'/,} ;done` won't return anything with `echo $OUTPUT` after the loop, for example. – Nikos Alexandris Jul 22 '21 at 14:49
  • 1
    They won't, as I said. You're creating and/or modifying variables in a different process. However, variables are not the only form of output: the loop can still print output directly to the shared stdout (as, in fact, this example does), and it can still operate on files which persist after the subshell exits. – Useless Jul 22 '21 at 16:40
  • Thanks (again)! The following somewhat elaborated example works exactly the way I need :-): Looping over `NAMES=x_myd11a1_lst_night_2019_01_01T01_30_00,x_myd21a1_lst_night_2019_01_01T01_30_00` via `while read -r NAME; do TMP=${NAME#*_} ;TMP2="${TMP%_*_*_*_*_*}" ;if [ -z $OUTPUT ] ;then OUTPUT+=${TMP2:-$TMP2} ;else OUTPUT+=${OUTPUT:+,$TMP2} ;fi ;done <<< ${NAMES//,/$'\n'*}` derives the `OUTPUT` variable `echo $OUTPUT`: `myd11a1_lst_night,myd21a1_lst_night`. – Nikos Alexandris Jul 22 '21 at 20:41
-5

Script file should be in Linux mode. Previously it was in dos mode. I changed it by using dos2unix filename.

e.g.:

dos2unix sshcopy.sh

Now it works for me.

pb2q
  • 58,613
  • 19
  • 146
  • 147
  • 1
    The answer proposed by [ruakh](http://stackoverflow.com/a/13122491/622391) was accepted by the asker. This means that the problem was _not_ related to the script's file format. – Simon MᶜKenzie Jun 25 '13 at 23:40