14

I have a file file.txt with contents like

i love this world

I hate stupid managers
I love linux

I have MS

When I do the following:

for line in `cat file.txt`; do
echo $line
done

It gives output like

I
love
this
world
I
..
..

But I need the output as entire lines like below — any thoughts ?

i love this world

I hate stupid managers
I love linux

I have MS
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
webminal.org
  • 44,948
  • 37
  • 94
  • 125

5 Answers5

27
while read -r line; do echo "$line"; done < file.txt
SiegeX
  • 135,741
  • 24
  • 144
  • 154
6

As @Zac noted in the comments, the simplest solution to the question you post is simply cat file.txt so i must assume there is something more interesting going on so i have put the two options that solve the question as asked as well:

There are two things you can do here, either you can set IFS (Internal Field Separator) to a newline and use existing code, or you can use the read or line command in a while loop

IFS="
"

or

(while read line ; do
    //do something
 done) < file.txt
tobyodavies
  • 27,347
  • 5
  • 42
  • 57
  • 5
    `IFS=$'\n'` is more readable. There's no need to put the `while` loop in a subshell. – Dennis Williamson Jan 27 '11 at 05:50
  • does that work Dennis?? I've been trying to put my `IFS` settings on to one line for months and gave up cause i thought it couldn't be done! – tobyodavies Jan 27 '11 at 05:54
  • 1
    I find the `( ... )` notation somewhat easier to read and performance is rarely a consideration in bash scripts. – tobyodavies Jan 27 '11 at 05:56
  • 1
    @toby Bash has the `$'string'` construct which treats certain backslash-escaped characters specially, `\n` being a newline. (see the bash man page for the full list). – SiegeX Jan 27 '11 at 06:17
  • 1
    @SiegeX, the irony being i use that syntax all the time to use escaped single quotes, but didn't know it let me use newlines – tobyodavies Jan 27 '11 at 06:19
  • 1
    @toby For the case you described I generally find it a bit more readable to use double quotes and just escape out the `$`. i.e. `echo "joe's foo\$bar"` vs `echo $'joe\'s foo$bar'` The other more common escape sequence you'll see is the NUL character `$'\0'` – SiegeX Jan 27 '11 at 06:49
  • mm, I don't do this by hand very often though, and when doing it programmatically on user input, i find having 1 character to escape (') preferable to having 2 (" and $) – tobyodavies Jan 27 '11 at 06:54
2

I believe the question was how to read in an entire line at a time. The simple script below will do this. If you don't specify a variable name for "read" it will stuff the entire line into the variable $REPLY.

cat file.txt|while read; do echo $REPLY; done

Dave..

Dave
  • 29
  • 1
  • Also note that this way, control is also passed back to the CLI after the file is read. This is especially important if you are piping the result of a command to the `while` instead of a file, which has an EOF, CLI output does not and would leave the command waiting for more. For example: `find . -name 'readme.txt' | while read line; do echo $line; done` (returned to user) vs `while read line; do echo $line; done | find . -name 'readme.txt'` (waits for input) – Neil Monroe Jan 24 '17 at 20:27
  • I had reason to use this and it worked perfectly, e.g., `% cat file | while read; do echo $REPLY | pipe_to_process_each_line >> file; done` – javafueled Jan 26 '20 at 13:34
1

You can do it by using read if the file is coming into stdin. If you need to do it in the middle of a script that already uses stdin for other purposes, you can temporarily reassign the stdin file descriptor.

#!/bin/bash
file=$1 

# save stdin to usually unused file descriptor 3
exec 3<&0

# connect the file to stdin
exec 0<"$file"

# read from stdin 
while read -r line
do
    echo "[$line]"
done

# when done, restore stdin
exec 0<&3
  • is there something wrong with redirecting to the while loop?? – tobyodavies Jan 27 '11 at 05:57
  • nope, just adding a different approach to highlight file descriptor manipulation which is esoteric but has its uses. – thatbrentguy Jan 27 '11 at 06:03
  • ...for instance, if you wanted to call some existing library function that was already written to use stdin but you wanted to have it draw from a file, you could use this technique to do so without having to recode the function – thatbrentguy Jan 27 '11 at 06:15
  • Bash libraries, an interesting concept... generally one would rather invoke a subshell even then though no? and bash function's have their own stdin anyway – tobyodavies Jan 27 '11 at 06:56
-2

Try

(while read l; do echo $l; done) < temp.txt

read: Read a line from the standard input and split it into fields.

Reads a single line from the standard input, or from file descriptor FD if the -u option is supplied. The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on, with any leftover words assigned to the last NAME. Only the characters found in $IFS are recognized as word delimiters.

Ulrich Schwarz
  • 7,598
  • 1
  • 36
  • 48
  • 1
    You don't need (and shouldn't use) the parens, these creates a superfluous sub-shell. Also, I didn't give you the -1 but I'm guessing the reason why somebody did was because your answer is an exact duplicate of mine given a few mins earlier. – SiegeX Jan 27 '11 at 05:45
  • I personally like the `( ... )` notation, i find it much easier to read... and speedups in the region of 1ms is rarely useful in bash – tobyodavies Jan 27 '11 at 06:00
  • @Siege: Naturally, one is going to get near-identical obvious answers at the same time. (Yours was not around when I composed; not quoting `help read` would have saved a minute, but cui bono?) – Ulrich Schwarz Jan 27 '11 at 06:10
  • @toby The main purpose for using the `while` loop with redirection is *because* it doesn't create a sub-shell, and it has nothing to do with speed due to an extra fork. It has everything to do with the fact that changes within the subshell are not reflected back into the parent shell. For example `i=0; (while read -r line; do ((i++)); done) < infile; echo $i` No matter how many lines 'infile' contains, the parent shell will *always* echo `0` for `i` due to the sub-shell – SiegeX Jan 27 '11 at 06:12
  • @SigeX true, however in most cases I consider that a good thing :D at the end of the day you need to know that there is a difference and why you choose one or the other – tobyodavies Jan 27 '11 at 06:16