Click to See Complete Forum and Search --> : reading lines from a text file (1 at a time) w/Bash


eflashj
04-02-2002, 05:00 PM
OK, this shouldn't be too tough. How do I read one line at a time from a text file in Bash?
I'd like to do something like:

for i in list.txt
do
some_work_that_depends_on $i
done

I had hoped that this would read the file one line at a time and assign it to $i until it reached EOF, but it doesn't. It's been a while since I tried anything like this in the shell and I just can't remember how.

Thanx for any help.

marvin
04-02-2002, 06:21 PM
This should do it.


for line in $(cat file.txt); do
echo line: $line;
done

TheLinuxDuck
04-02-2002, 06:38 PM
Marvin:

Actually, that won't work as-is, because a for loop treats spaces as an individual item. So, your echo statement will print each space-delimited item as a line... You'll have to do some funk on it to get it to work correctly. My hack is this: When I cat the file, I replace all spaces with '\r's. That way, a line is treated as a whole line, only delimited by it's newline '\n'. And when I deal with the line later, I remove the '\r'.

This obviously won't work if the file could contain '\r's, but i don't see why a *nix file would.. (^=

Here is my addition:

for line in $(cat /etc/passwd | tr ' ' '\r' ); do
echo line: $line | tr '\r' ' '
done

TheLinuxDuck
04-02-2002, 06:39 PM
eflashj:

Here is the link for a really good bash HOW-TO. I use it all the time when I have questions.
http://linuxdoc.org/LDP/abs/html/

marvin
04-02-2002, 08:05 PM
Originally posted by TheLinuxDuck:
<STRONG>Marvin:

Actually, that won't work as-is, &lt;snip&gt; </STRONG>

OOPS :o Yes, you're right, stupid me didn't test it before I posted it... I'll go stand in the corner for a while :)

Strogian
04-02-2002, 09:08 PM
Or, you could just change the IFS variable to "&lt;newline&gt;" (i.e. IFS="
") That will make bash only split the expansion based on newlines. (IFS is normally set to "&lt;space&gt;&lt;tab&gt;&lt;newline&gt;") Hehe.. I JUST read that part of the bash man page, too. :D

TheLinuxDuck
04-03-2002, 10:26 AM
Originally posted by Strogian:
<STRONG>Or, you could just change the IFS variable to "&lt;newline&gt;" (i.e. IFS="
") That will make bash only split the expansion based on newlines. (IFS is normally set to "&lt;space&gt;&lt;tab&gt;&lt;newline&gt;") Hehe.. I JUST read that part of the bash man page, too. :D</STRONG>

I saw that too, but tried it, and it didn't work.. (^=

TheLinuxDuck
04-03-2002, 10:28 AM
Originally posted by marvin:
<STRONG>OOPS :o Yes, you're right, stupid me didn't test it before I posted it... I'll go stand in the corner for a while :)</STRONG>

(^= I've done that so many times.. don't worry, be happy, and eat cheese. (if you like cheese).

You should have seen how I was trying to do this before I saw yer first post! Whoa!

bwkaz
04-03-2002, 01:44 PM
Set IFS to this:

$'\n'

Then set it back (after you're done) to this:

$' \t\n'

That's dollar-sign, apostrophe, &lt;stuff&gt;, apostrophe.

Strogian
04-03-2002, 05:00 PM
Originally posted by TheLinuxDuck:
<STRONG> I saw that too, but tried it, and it didn't work.. (^=</STRONG>

Odd.. It works for me in a plain console. Lemme try it in a bash script.

Yep, works here too:

IFS="
"
joe="This is a really cool program.
It works perfectly.
I love it."

for line in $joe
do
echo "One Line Read"
done


Outputs:
One Line Read
One Line Read
One Line Read

I'm not sure how you'd work file input into that, but setting IFS does work. :) (I haven't gotten to the part that talks about what bwkaz is doing yet, but his way does look a tad bit cleaner ;))

TheLinuxDuck
04-03-2002, 05:05 PM
Word. I didn't do it right.... and that would explain why it didn't work right.. (^=

Qool.

As for setting IFS to newline and such, another way to do it would be to copy IFS into another variable, and then just reassign when done.

IFSCopy=$IFS
IFS=$'\n'
# do stuff

IFS=$IFSCopy


Something like that anyway.

Through the link I posted above, I found some example code that someone did.. it's basically a bash equivalent of C's string library. I was most impressed.. they converted most of the string function calls to a bash equivalent.. It's amazing what bash can do.

Word, yo's.. thanks for the pointers and info! (even though this thread wasn't my thread, I still learnededed some stuffs)

eflashj
04-04-2002, 12:30 PM
Thanx for all the help. I got it done, but not quite the way you all did. My solution looked like this:

num_lines=wc &lt; INPUT_FILE | cut -d" " -f7
while [ $num_lines -gt 0 ]
do
line=`cat INPUT_FILE | tail -n $num_lines | head -n 1
do_some_work_based_on $line
num_lines=$(($num_lines-1))
done

[ 04 April 2002: Message edited by: eflashj ]