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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?

share|improve this question
up vote 5 down vote accepted

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.

share|improve this answer
    
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 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 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 at 21:49
    
@tobi: Please start a new question. Thank you. – Cyrus Jan 4 at 8:18

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".

share|improve this answer
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 at 20:00
    
@Wildcard Misprint, thanks. – jimmij Jan 3 at 20:05
    
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 at 21:05

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/.

share|improve this answer

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()
share|improve this answer

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.