4

Let's say I have 2 files each containing lines which start with a 'b' character and I only want to merge these lines in the same order they appear in the first file.

First File (1.txt)

b 12 32
b 23 43
b 23 63

Second File (2.txt)

a 1322
c 233
g 23324
s 24352

b
h vd2 3f4g

a 2t42
c 34536
g h3443e
s 24h455

b
h 3434gggdfbv4

a 423gwg
c f24bv
g 34g 45h
s 4zth5

b
h 3456zh543

You can see that in the second file the lines which start with a 'b' character don't contain any more information while in the first file I have lines only starting with a 'b' followed by some integer values.

What I need now is something which gets the integers from the first file and puts them into the second files 'b' lines the same way the appear in the first file. So the second file should in the end look like this:

merged file (3.txt)

a 1322  
c 233  
g 23324  
s 24352  

b 12 32  
h vd2 3f4g  

a 2t42  
c 34536  
g h3443e  
s 24h455  

b 23 43  
h 3434gggdfbv4  

a 423gwg  
c f24bv  
g 34g 45h  
s 4zth5  

b 23 63  
h 3456zh543  

join command seems to be able to do what I want but I can't find a way to tell it to only work on lines matching the leading 'b' character. I also thought about a loop walking through file 1 to get the line numbers matching the patter '^b' and then use them to replace the lines matching pattern '^b' in file 2 but again I can't find a working solution. Does anyone have an idea to accomplish my task with a one-liner or a short bash script?

4 Answers 4

5

With GNU sed:

sed -e '/^b/{R 1.txt' -e 'd}' 2.txt

if you want to edit file 2.txt "in place", add sed's option -i.

4
  • Thx Cyrus! I am accepting your answer even though jimmijs is also very helpful for me. I was hoping for a 'sed' solution though which you served and therefore I accepted yours. Could you explain me the magic happening in the curly brackets plz? I'm slightly confused by the single quote usage and what is the 'd' doing?
    – tobi
    Jan 3, 2016 at 20:59
  • 1
    Because it is not possible to use '/^b/{R 1.txt;d}' I splitted this in two sed scripts with option -e. After R 1.txt it is necessary to insert a newline or end the first script and start a second script. d deletes current pattern space. In this case the lines which begin with b from file 2.txt
    – Cyrus
    Jan 3, 2016 at 21:07
  • What if the content shouldn't go into the exact same line but in a line with a different search pattern? Let's say the line in the second file starts with a 'c' instead of 'b'. Is that also possible?
    – tobi
    Jan 3, 2016 at 21:49
  • @tobi: Please start a new question. Thank you.
    – Cyrus
    Jan 4, 2016 at 8:18
4

With awk:

awk 'NR==FNR{a[++i]=$0;next}$0=="b"{$0=a[++j]}1' file1 file2

First we fill array a with the content of file1 and when file2 is being processed the array is printed in place of the lines which contain only letter "b".

2
  • 1
    Why are you only resetting $2 instead of $0? That will give you the b character showing twice on each altered line in the output.
    – Wildcard
    Jan 3, 2016 at 20:00
  • Thx jimmij for the answer and the text edit. I thought highlighting the lines in file three using blockqoute would help increasing readibillity and understanding of what I actually want (I'm always concerned about my english and whether someone understands what I want or not. Anyways, I accepted the 'sed' solution 'cause' it's shorter and I don't know much about 'awk' yet. I guess I can only accept 1 answer right? (Yes I am new to this)
    – tobi
    Jan 3, 2016 at 21:05
2

Probably it would be easier in Perl, but I haven't learned Perl yet.

You can do it in awk with a bit of trickery:

awk 'NR == FNR { line[NR] = $0; next } /^b/ { $0 = line[++whichline] } 1' 1.txt 2.txt > 3.txt

This stores all the lines from the first file into the array called line and then puts those lines into place in the second file in the lines matching /^b/.

2

Python can help here:

    #!/bin/env python
    fileA=open('filea','r')
    fileB=open('fileb','r')
    resultFile = open('resultfile','w')
    linesA=fileA.readlines()
    i=0
    for line in fileB:
      if line.lstrip().startswith('b'):
        resultFile.write(linesA[i].rstrip())
        i=i+1
      else:
        resultFile.write(line)
   fileA.close()
   fileB.close()
   resultFile.close()

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .