16

I have a script variable which is multi-line. How do i traverse this variable to read it line by line and process each line the way I want?

1

2 Answers 2

37

Consider the following multi-line variable

x=$(echo -e "a\nb\nc d e")

and a simple process for each line: just echo it with a prefix=LINE: and with single quotes around the line. Either of the following codes will satisfy that requirement:

while read line; do echo "LINE: '${line}'"; done <<< "$x"

or

while read line; do echo "LINE: '${line}'"; done < <(echo "$x")

Neither creates a subshell (so you can, e.g., set variables in the loop and access them outside of it), and both output

LINE: 'a'
LINE: 'b'
LINE: 'c d e'

But suppose instead you have

x=$(echo -e "a \n b\nc d e")
# note--------^--^

and that leading and trailing whitespace matter for your application (e.g., parsing Git porcelain). Both the above codes will give exactly the same output for the latter variable/data as for the former, which is not what you want. To preserve leading and trailing whitespace, replace while read line with while IFS= read -r line . I.e., either of the following codes

while IFS= read -r line; do echo "LINE: '${line}'"; done <<< "$x"

or

while IFS= read -r line; do echo "LINE: '${line}'"; done < <(echo "$x")

will produce

LINE: 'a '
LINE: ' b'
LINE: 'c d e'

See Greg Wooledge's excellent Bash FAQ for details.

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

5 Comments

this is a perfect solution, just curious, why not just x="a\nb\nc d e"?
@SenthilKumar, that string contains 10 charactes: 'a', '\', 'n', 'b', etc. The "\n" are not special inside double quotes. In bash, one could write $"a\nb\nc d e" to have real newlines embedded in the string. The "-e" flag tells echo to process "\n" as a new line, not two indvidual characters.
@chepner: thx, $ was new to me, but it works with single quotes $'a\nb\nc d e'
@Karoly: my mistake, I used the wrong quotes. Double quotes are for gettext translations; single quotes are for backslash expansions.
It should be mentioned that this solution only works because echo adds a trailing newline; in other words, it alters the variable to parse. This might or might not be acceptable for the OP. Without the trailing newline, read would completely miss the last line. For details, see unix.stackexchange.com/a/9789
5

Although I typically use "while read" for processing multi-line variables, I recently had an instance where it removed the leading space from each line in a file. Using this instead fixed my issue:

printf '%s\n' "$var" | while IFS= read -r line
do
   echo "$line"
done

Code taken from this Unix Stack Exchange answer.

Edit: updated to fix last line issue as suggested by Nicolae Iotu

2 Comments

Nice solution, but you will need to end printf with a new line to make it process the last line: printf '%s\n' "$var" ...
Good point, thank you. I have updated my answer with the changes you suggested.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.