3

I know how to merge two tables to print alternative lines in a new file, but I want to merge every two lines from file1.txt with one line from file2.txt. As an example:

file1.txt is

A a aa
B b bb 
C c cc
D d dd

and file2.txt is

E e ee 
F f ff

I want to have

A a aa
B b bb 
E e ee 
C c cc
D d dd
F f ff
muru
  • 207,228
Negar
  • 101

3 Answers3

7

Using GNU sed, you can read and insert one line from the second file after every other line ("two skip two") of the first:

$ sed '2~2R file2.txt' file1.txt
A a aa
B b bb 
E e ee 
C c cc
D d dd
F f ff

Slightly more long-winded implementation of the same in awk:

awk '{print} !(NR%2) {if ((getline < "file2.txt") > -1) print}' file1.txt
steeldriver
  • 142,475
6

You can use the paste command for this:

% paste -d '\n' - - file2.txt < file1.txt
A a aa
B b bb 
E e ee 
C c cc
D d dd
F f ff

paste, by default, takes lines from each input file, then merges them into a single line separated by tabs. Using -d '\n', we tell it to use newlines as the separator instead. - is standard input, which is redirected in from file1.txt (< file1.txt). So paste takes one line from standard input, then another line from standard input (effectively two lines from file1.txt, then a line from file2.txt and prints them out separated by newlines.

muru
  • 207,228
2

Original shellscript

I thought the following shellscript would do it. The trick is to open the two files on separate file descriptors (here #4 and #5).

#!/bin/bash

while read -r -u 4 line1 && read -r -u 4 line2 && read -r -u 5 line3
do
  echo "$line1"
  echo "$line2"
  echo "$line3"
done 4<file1.txt 5<file2.txt

Test

Make the shellscript executable and run it,

$ ./myscript 
A a aa
B b bb
E e ee
C c cc
D d dd
F f ff

The original shellscript stops, when reading to the end of file in one of the input files (so that only matching 2+1 lines are written to the output).

Modified shellscript

The following shellscript will continue reading and writing until all the files have reached end of file (so that all available lines are written to the output). This should match what the OP wants.

#!/bin/bash

end1=false
end2=false
cont=true
while $cont
do
 read -r -u 4 line1
 if [ $? -eq 0 ]
 then
  echo "$line1"
 else
  end1=true
 fi

 read -r -u 4 line2
 if [ $? -eq 0 ]
 then
  echo "$line2"
 else
  end1=true
 fi

 read -r -u 5 line3
 if [ $? -eq 0 ]
 then
  echo "$line3"
 else
  end2=true
 fi

 if $end1 && $end2  # modify this line to change when to stop
 then
  cont=false
 fi
done 4<file1.txt 5<file2.txt
sudodus
  • 47,684