Score:0

echo command breaks lines, being used in loops

br flag

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
pLumo avatar
in flag
`for i in $(cat foo)` does not loop lines but words split by your field separator (`IFS`).
br flag
So, how I can loop lines / change IFS mode to loop lines, not words?
pLumo avatar
in flag
If you tell us what you actually want to do, we can help you do it properly using `sed` or so.,
Score:4
in flag

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

br flag
How I can use 'grep' instead?
pLumo avatar
in flag
We cannot know, because we don't know what you want to do, see my last comment on your question.
Score:2
ph flag

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]$    
br flag
If I want to go with your solution, but also to add a conditional statement inside my for loop, then what will be "$i"? I mean, something like this: for i in $(while read line ; do echo $line ; done < foo); do if [ grep -c a "$i" -gt 1 ]; then echo "$i";fi;done
hr flag
Note that `$line` should be quoted `"$line"` for similar reasons (otherwise it will be word split into separate tokens - try with `a b` in place of `a b` for example).
hr flag
... as well, `read` would still remove any leading whitespace and expand escape sequences by default, so more generally if you want to echo lines *exactly* you'd want `while IFS= read -r line; do ...` or (to include a possibly improperly terminated last line) `while IFS= read -r line || [[ -n "$line" ]]; do ...`
bac0n avatar
cn flag
@JosefKlimuk ```while read -r; do if ! grep -oe 'a' <<< "$REPLY" | sed -n 2q1; then echo "$REPLY"; fi; done < text```, `-c` only count matched lines, and since you only have one line it will never be more than 1. I like to use sed to count occurrence as it can return an exit status.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.