echo command breaks lines, being used in loops [duplicate]

In my file 'foo' there is a first line: 'a b', and the second line: 'c d':

$ cat foo
a b 
c d

I want to print in terminal in loop these two lines: one after another:

$ for i in $(cat foo); do echo $i; done

But in the output 'echo' command breaks the order, so instead of having:

a b
c d

I actually have:

a
b
c
d

Solution 1:

for i in $(cat foo) does not loop lines but words (or fields) split by your field separator $IFS. It default to \n\t (space, newline, tab).

If you change your field separator to newline only, you can use your command as is (Disclaimer: please read below!):

IFS=$'\n'
for i in $(cat foo); do echo $i; done

You might want to make a backup of IFS to restore it later:

OLD_IFS="$IFS"
.
.
.
IFS="$OLD_IFS"

Output:

a b
c d

However, this is considered bad practice.

  • Bit Better: while IFS= read -r line; do ... done < file
  • Much better: Use a dedicated tool for your task such as grep, sed or awk.

Please read Why is using a shell loop to process text considered bad practice?.

Solution 2:

You can use while read for this purpose

[/tmp]$ while read line ; do echo $line ; done < foo                                     
a b
c d

Adding a separator for your understanding

[/tmp]$ while read line ; do echo $line ; echo "----" ; done < foo                       
a b
----
c d
----
[/tmp]$