How to read complete line in 'for' loop with spaces

I am trying to run a for loop for file and I want to display whole line. But instead its displaying last word only. I want the complete line.

for j in `cat ./file_wget_med`
do
echo $j
done

result after run:

Found.

Here is my data:

$ cat file_wget_med
2013-09-11 14:27:03 ERROR 404: Not Found.
1

7 Answers

for loop splits when it sees any whitespace like space, tab, or newline. So, you should use IFS (Internal Field Separator):

IFS=$'\n' # make newlines the only separator
for j in $(cat ./file_wget_med)
do echo "$j"
done
# Note: IFS needs to be reset to default!
9

for loops split on any whitespace (space, tab, newline) by default; the easiest way to work on one line at a time is to use a while read loop instead, which splits on newlines:

while read i; do echo "$i"; done < ./file_wget_med

I would expect your command to spit out one word per line (that's what happened when I tested it out with a file of my own). If something else is happening, I'm not sure what could be causing it.

9
#!/bin/bash
files=`find <subdir> -name '*'`
while read -r fname; do echo $fname
done <<< "$files"

Verified working, not the one liner you probably want but it's not possible to do so elegantly.

2

Here is a slight extension to Mitchell Currie's answer, that I like because of the small scope of side effects, which avoids having to set a variable:

#!/bin/bash
while read -r fname; do echo $fname
done <<< "`find <subdir>`"
1

I would write it like this:

cat ./file_wget_med | while read -r j
do echo $j
done

as it requires least changes in the original script (except for the solution using IFS, but it modifies bash behavior not only for this loop control statement).

1

Mapfile is a convenient way to read lines from a file into an indexed array, not as portable as read but slightly faster. By using for loop you avoid creating a subshell.

#!/bin/bash
mapfile -t < file.txt
for line in "${MAPFILE[@]}"; do echo $line
done

Keep in mind when using pipelines, it will put the while loop in a subshell. Changes inside the while loop like variables will not propagate to outer part of the script.

Example:

#!/bin/bash
a=0
printf %s\\n {0..5} | while read; do ((a++))
done
echo $a # 'a' will always be 0.

(Better solution):

#!/bin/bash
b=0
while read; do ((b++))
done < <(printf %s\\n {0..5})
echo $b # 'b' equal to 6 (works as expected).
1

Dandalf got real close to a functional solution, but one should NOT EVER be trying to assign the result of unknown amounts of input (i.e. find ~/.gdfuse -name '*') to variables! Or, at least be trying to do such a thing via an array variable; if you insist on being so lazy! So, here's Dandalf's solution done without the dangerous maneuver; and in all in one line

while read -r fname; do echo $fname;
done <<< `find ~/.gdfuse -name '*'
1

You Might Also Like