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.

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
  • 4
    And put care about single quotes on IFS because IFS=$"\n" will split also "nn" strings. I found set IFS more reliable than use more complicated syntax or functions. – erm3nda Aug 25 '15 at 4:08
  • 19
    apparently it is advised to unset IFS afterwards, so that other commands are not influenced in this same shell. – Boris Däppen Oct 8 '15 at 14:49
  • 2
    What does the $ mean in IFS=$'\n'? – Ren Dec 4 '16 at 8:02
  • 1
    $ makes line breaks work inside the string. This should also be done with local IFS=$'\n' inside a function. – Andy Ray Mar 3 '17 at 18:34
  • 1
    @Renn that's $'...' known "ANSI-C Quoting" – αғsнιη Jun 7 at 16:43

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.

  • 5
    This is also a good alternative to for i in `ls`; do echo $1; done, by piping the output to the while command: ls|while read i; do echo $i; done. This works on file/folder names with spaces, without needing to change environment variables. Very good answer. – jishi Jun 1 '15 at 21:23
  • the while didn't handle the first and last lines very, not as well as the for loop with IFS – grantbow Jul 28 '15 at 15:16
  • @jishi Since it's primarily designed for display, and is responsive to terminal-window size and such, ls is not considered safe for use with | (the pipe operator). find is more flexible in addition to being safer for this purpose. – SeldomNeedy Nov 20 '15 at 21:48
  • 2
    This is a GREAT answer, I used it to turn a list I had into PLIST entries for an IOS app I was developing on mac OSX. I replaced the file input by piping the clipboad using pbpaste -> pbpaste | while read t; do echo "<string>$t</string>"; done – Big Rich Mar 8 '16 at 15:43
  • 2
    ls -1 may be used with | to guarantee one-per-line unformatted output – AndreyS Scherbakov May 7 '16 at 0:08
#!/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.

  • 1
    a here-string! most elegant of all other solutions IMO – Eliran Malka Jan 25 '17 at 22:20

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> -name '*'`"

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

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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