56

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

4 Answers 4

87

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

Sign up to request clarification or add additional context in comments.

2 Comments

Does IFS= set the IFS to null character? Why do you need it in this case?
@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".)
33

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

while read line ; do
    echo $line
done < <( ... code ... )

Comments

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

3 Comments

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

1 Comment

The answer proposed by ruakh was accepted by the asker. This means that the problem was not related to the script's file format.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.