sanjeev prakasham sanjeev prakasham - 6 months ago 21
Perl Question

File search and replace with Tie::File

My search and replace is not working, nor is it throwing any error.

I tried to modify the code and provide the input where it is working. I'm not sure where the error occurs.

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;

use Tie::File;
use v5.10;
use File::Compare;

my $VAR; $VAR=$ARGV[0];chomp $VAR;

my $nam=qq~file_name~;

my @lines;

our $s1="var1";
our $s2="var2";

if ('$s1' ne '$s2'){
replace();
}

sub replace {

chomp $s1;chomp $s2;

tie @lines, 'Tie::File', "$nam" or die " can't open the file\n";

foreach ( @lines ) {
s/$s2/$s1/g; # replacing the strings
}

untie @lines;
};

Answer

Tie::File rarely helps. If you're going to do for (@lines) with a tied file, you're going to make things abysmally slow and use way more memory that you would have if you hadn't used Tie::File.

#!/usr/bin/perl

use strict;
use warnings;

@ARGV = 'file_name';
$^I = '';   # Like the -i command line option

while (<>) {
   s/var2/var1/g;
   print;
}

This is basically the samething as doing

perl -i -pe's/var2/var1/g' file_name

If creating files is not an option, then I'd use the following:

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

my $qfn = 'file_name';

my @lines;
{
   open(my $fh, '<', $qfn);
   @lines = <$fh>;
}

{
   open(my $fh, '>', $qfn);
   s/var2/var1/g for @lines;
   print($fh @lines);
}

This way faster than with Tie::File — 30x faster, IIRC. It also uses way less memory than with Tie::File.