Copy selected lines from one file and paste those lines into another file after the selected line

Here's my question: let's say I have a file file1.txt

with content:

abc.. 
def.. 
ghi.. 
def..

      

and a second file file2.txt

with content:

xxx..
yyy..
zzz..

      

Now I want to copy the whole line starting with "def" in file1.txt

before file2.txt

and add after the line "yyy ..." infile2.txt

Expected Result:

xxx...
yyy...
def...
def...
zzz...

      

I am very new in perl, I tried writing simple code for this, but in the end the output is only appended to the end of the file

#!/usr/local/bin/perl -w 
use strict; 
use warnings;
use vars qw($filecontent $total);
my $file1 = "file1.txt";
open(FILE1, $file1) || die "couldn't open the file!";
open(FILE2, '>>file2.txt') || die "couldn't open the file!";
  while($filecontent = <FILE1>){
    if ( $filecontent =~ /def/ ) {
      chomp($filecontent);
       print FILE2 $filecontent ."\n";
      #print FILE2 $filecontent ."\n" if $filecontent =~/yyy/;
    }  
  } 
 close (FILE1); 
 close (FILE2);

      

perl program output

xxx...
yyy...
zzz...
def...
def...

      

+3


source to share


3 answers


I would use a temporary file.

  • Read and print all lines (up to temp) from FILE2 until you hit "yyy"
  • Read and print all "def" lines (up to temp) from FILE1
  • Read and print (temporarily) the rest of FILE2
  • Rename the temp file to FILE2


use strict; 
use warnings;

my $file1 = "file1.txt";
my $file2 = "file2.txt";
my $file3 = "file3.txt";

open(FILE1, '<', $file1) or die "couldn't open the file!";
open(FILE2, '<', $file2) or die "couldn't open the file!";
open(FILE3, '>', $file3) or die "couldn't open temp file";

while (<FILE2>) {
  print FILE3;
  if (/^yyy/) {
    last;
  }
}

while (<FILE1>) {
  if (/^def/) {
    print FILE3;
  }
}

while (<FILE2>) {
  print FILE3;
}

close (FILE1); 
close (FILE2);
close (FILE3);

rename($file3, $file2) or die "unable to rename temp file";

      

+5


source


The easiest way to do this is with a Tie::File

module, which allows you to access the file as a simple array of strings.

I also used first_index

from List::MoreUtils

to find where to insert records.

use strict;
use warnings;

use Tie::File;
use List::MoreUtils qw/ first_index /;

tie my @file1, 'Tie::File', 'file1.txt' or die $!;
tie my @file2, 'Tie::File', 'file2.txt' or die $!;

my $insert = first_index { /^yyy/ } @file2;

for (@file1) {
  if ( /^def/ ) {
    splice @file2, ++$insert, 0, $_;
  }
}

      



output (file2.txt)

xxx..
yyy..
def.. 
def..
zzz..

      

Your test data doesn't cover it, but records from file1.txt

are inserted file2.txt

in the order they appear.

+2


source


You might want to try the module IO::All

:

use IO::All;
my ($f1, $f2, $i) = (io('file1.txt'), io('file2.txt'), 1);
for (@$f2) {
    splice(@$f2, $i, 0, grep /^def/, @$f1), last
        if /^yyy/;
    $i++;
}

      

+2


source







All Articles