I read that it is bad to write things like for line in $(command), the correct way seem to be instead:

command | while IFS= read -r line; do echo $line; done

This works great. But what if what I want to iterate on is the contents of a variable, not the direct result of a command?

For example, imagine that you create the following file quickfox:

The quick brown
foxjumps\ over -
lazy ,

I would like to be able to do something like this:

# This is just for the example,
# I could of course stream the contents to `read`
variable=$(cat quickfox);
while IFS= read -r line < $variable; do echo $line; done; # this is incorrect

In modern shells like bash and zsh, you have a very useful `<<<' redirector that accepts a string as an input. So you would do

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

Otherwise, you can always do

echo "$variable" | while IFS= read -r line ; do echo $line; done
|improve this answer|||||
  • Sorry, I should have thought about echoing the contents of course. But thanks for the quick answer anyway! – Jonathan H Apr 11 '16 at 19:17
  • 1
    you need to double-quote $variable when you use it, otherwise the while loop will get only one line of input. See, for example, the difference in output between echo $variable vs echo "$variable" or cat <<< $variable vs cat <<< "$variable". – cas Apr 11 '16 at 22:54
  • @cas Actually it depends on what is inside $variable. In the case presented by the OP ("variable=$(cat quickfox)") it works without the additional quotes. But for the general case, you're right. I edit my answer. Thanks. – lgeorget Apr 12 '16 at 6:55
  • The variable=$(cat quickfox) in the OP's question itself provides an example of what I was talking about. Using that $variable inside double-quotes includes the newlines, using it without has the newlines translated to spaces by the shell. If you're reading and processing line-by-line, this makes a huge difference - with the former you have multiple input lines, with the latter you have just one input line. The input data is superficially similar but, in practice, completely different in those two cases. – cas Apr 12 '16 at 8:57
  • for example: with that input data, cat <<< "$variable" | wc -l returns 5. cat <<< $variable | wc -l returns 1. If you want/need to preserve whitespace (including newlines, tabs, single or multiple spaces) in a variable then you MUST double-quote the variable when you use it, otherwise they'll all be transformed into a single space between each "word". – cas Apr 12 '16 at 8:59

Example how to iterate over env variables with multi-line values:

for var in $(compgen -v | grep -Ev '^(BASH)'); do
    echo "$var=${!var}"


  1. $(compgen -v | grep -Ev '^(BASH)') - grep a list of env keys, skip those that started with BASH
  2. echo "$var=${!var}" - print key=value pairs
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.