Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping through lines in a file in bash, without using stdin

I am foxed by the following situation.

I have a file list.txt that I want to run through line by line, in a loop, in bash. A typical line in list.txt has spaces in. The problem is that the loop contains a "read" command. I want to write this loop in bash rather than something like perl. I can't do it :-(

Here's how I would usually write a loop to read from a file line by line:

while read p; do
  echo $p
  echo "Hit enter for the next one."
  read x
done < list.txt

This doesn't work though, because of course "read x" will be reading from list.txt rather than the keyboard.

And this doesn't work either:

for i in `cat list.txt`; do
    echo $i
    echo "Hit enter for the next one."
  read x
done

because the lines in list.txt have spaces in.

I have two proposed solutions, both of which stink:

1) I could edit list.txt, and globally replace all spaces with "THERE_SHOULD_BE_A_SPACE_HERE" . I could then use something like sed, within my loop, to replace THERE_SHOULD_BE_A_SPACE_HERE with a space and I'd be all set. I don't like this for the stupid reason that it will fail if any of the lines in list.txt contain the phrase THERE_SHOULD_BE_A_SPACE_HERE (so malicious users can mess me up).

2) I could use the while loop with stdin and then in each loop I could actually launch e.g. a new terminal, which would be unaffected by the goings-on involving stdin in the original shell. I tried this and I did get it to work, but it was ugly: I want to wrap all this up in a shell script and I don't want that shell script to be randomly opening new windows. What would be nice, and what might somehow be the answer to this question, would be if I could figure out how to somehow invoke a new shell in the command and feed commands to it without feeding stdin to it, but I can't get it to work. For example this doesn't work and I don't really know why:

while read p; do 
  bash -c "echo $p; echo ""Press enter for the next one.""; read x;"; 
done < list.txt

This attempt seems to fail because "read x", despite being in a different shell somehow, is still seemingly reading from list.txt. But I feel like I might be close with this one -- who knows.

Help!

like image 270
Yannick Avatar asked Nov 01 '13 13:11

Yannick


1 Answers

You must open as a different file descriptor

while read p <&3; do
    echo "$p"
    echo 'Hit enter for the next one'
    read x
done 3< list.txt

Update: Just ignore the lengthy discussion in the comments below. It has nothing to do with the question or this answer.

like image 155
Jo So Avatar answered Oct 23 '22 06:10

Jo So