Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I wanted to know if there is any way of reading from two input files in a nested while loop one line at a time. For example, lets say I have two files FileA and FileB.

FileA:

[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3

FileB:

[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3

Current Sample Script:

[jaypal:~/Temp] cat read.sh 
#!/bin/bash
while read lineA
    do echo $lineA 
    while read lineB
        do echo $lineB 
        done < fileb
done < filea

Execution:

[jaypal:~/Temp] ./read.sh 
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3

Problem and desired output:

This loops over FileB completely for each line in FileA. I tried using continue, break, exit but none of them are meant for achieving the output I am looking for. I would like the script to read just one line from File A and then one line from FileB and exit the loop and continue with second line of File A and second line of File B. Something similar to the following script -

[jaypal:~/Temp] cat read1.sh 
#!/bin/bash
count=1
while read lineA
    do echo $lineA 
        lineB=`sed -n "$count"p fileb`
        echo $lineB
        count=`expr $count + 1`
done < filea

[jaypal:~/Temp] ./read1.sh 
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3

Is this possible to achieve with while loop?

share|improve this question
add comment

4 Answers

up vote 10 down vote accepted

You can use file descriptors in the redirection to the while loop, then have read read from the file descriptors.

#! /bin/bash    
while true; do
  read -r lineA <&3
  read -r lineB <&4
  if [ -z "$lineA" -o -z "$lineB" ]; then
    break
  fi
  echo "1: "$lineA
  echo "2: "$lineB
done 3<fileA 4<fileB

Not tested much. Might break on empty lines.

File descriptors number 0, 1, and 2 are already used for stdin, stdout, and stderr, respectively. File descriptors from 3 and up are (usually) free. The bash manual warns from using file descriptors greater than 9, because they are "used internally".

share|improve this answer
    
Thanks @lesmana. It's much clearer now. –  JS웃 Dec 12 '11 at 1:30
add comment

Open the two files on different file descriptors. Redirect the input of the read built-in to the descriptor that the file you want is connected to. In bash/ksh/zsh, you can write read -u 3 instead of read <&3.

while IFS= read -r lineA && IFS= read -r lineB <&3; do
  echo "$lineA"; echo "$lineB"
done <fileA 3<fileB

This snippet stops when the shortest file has been processed. See Reading two files into an IFS while loop -- Is there a way to get a zero diff result in this case? if you want to keep processing until the end of both files.

See also When would you use an additional file descriptor? for additional information on file descriptors, and Why is `while IFS= read` used so often, instead of `IFS=; while read..`? for an explanation of IFS= read -r.

share|improve this answer
    
Thanks @Gilles for the additional links on file descriptor. –  JS웃 Dec 12 '11 at 1:31
    
@Gilles perhaps I misunderstood you, but I could not make the loop process the longest file entirely (which is always $fileA in my case), so I made that into a separate question, being: is there a way to write the loop so that diff doesn't notice any difference between input and output? unix.stackexchange.com/questions/26780/… the closest i could get was diff only finding one line of difference. –  ixtmixilix Dec 14 '11 at 11:36
add comment

I know you want a shell script, but you might want to take a look at the paste command.

share|improve this answer
    
Thanks @lutzky. paste is cool too. –  JS웃 Dec 19 '11 at 20:37
add comment

Alternatively, I suppose you could slurp the file into an array variable tying each line of the file into array[line_of_file_index] using bash's mapfile command. However, I am not sure if it is only for Bash3 higher or Bash4.

http://wiki.bash-hackers.org/commands/builtin/mapfile

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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