5

Assume a file file with multiple lines.

$ cat file
foo
bar
baz

Assume further that I wish to loop through each line with a while-loop.

$ while IFS= read -r line; do
$   echo $line
$   # do stuff
$ done < file
foo
bar
baz

Finally, please assume that I wish to pass lines stored in a variable rather than lines stored in a file. How can I loop through lines that are saved as a variable without receiving the below error?

$ MY_VAR=$(cat file)
$ while IFS= read -r line; do
$   echo $line
$   # do stuff
$ done < $(echo "$MY_VAR")
bash: $(echo "$MY_VAR"): ambiguous redirect
Cyrus
  • 84,225
  • 14
  • 89
  • 153
Michael Gruenstaeudl
  • 1,609
  • 1
  • 17
  • 31
  • `echo $line` is not the same as `echo "$line"`. See [BashPitfalls #14](http://mywiki.wooledge.org/BashPitfalls#echo_.24foo). – Charles Duffy Jun 26 '17 at 20:06
  • Also, all-caps variable names are used for variables with meaning to the shell or OS, whereas names with lowercase characters are guaranteed not to conflict with system operation. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, fourth paragraph. – Charles Duffy Jun 26 '17 at 20:06

2 Answers2

5

You have several options:

  • A herestring (note that this is a non-POSIX extension): done <<<"$MY_VAR"
  • A heredoc (POSIX-compliant, will work with /bin/sh):

    done <<EOF
    $MY_VAR
    EOF
    
  • A process substitution (also a non-POSIX extension, but using printf rather than echo makes it more predictable across shells that support it; see the APPLICATION USAGE note in the POSIX spec for echo): done < <(printf '%s\n' "$MY_VAR")


Note that the first two options will (in bash) create a temporary file on disk with the variable's contents, whereas the last one uses a FIFO.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
5

< needs to be followed by a filename. You can use a here-string:

done <<< "$MY_VAR"

or process substitution:

done < <(echo "$MY_VAR")
Barmar
  • 741,623
  • 53
  • 500
  • 612