Reputation: 825
I am running the following code to open a file (test) and edit(search and replace) it. Program seems to open the file but instead of replacing it deletes everything in the file. I am not sure why that is happening. Can anyone help me out here?
#!use/bin/perl
use strict;
use warnings;
my $line = $ARGV[0];
my $find = '\s{6}seqfile\s=\sinfile';
my $replace = '\s{6}seqfile\s=\sinfil2';
open (FILE, ">/home/shubhi/Desktop/pamlrun/test") || die "cant open file \n";
my @body = <FILE>;
foreach $line(@body)
{
(s/$find/$replace/g);
{
print FILE "$line";
}
}
close(FILE);
print "reached here\n";
exit;
Upvotes: 0
Views: 1169
Reputation: 64909
It looks like you want in-place editing magic. The easiest way to get this is to use $^I
with the magic of @ARGV
plus <>
(look for null filehandle in the I/O Operators section):
#!/usr/bin/perl
use strict;
use warnings;
my $find = qr/\s{6}seqfile\s=\sinfile/;
my $replace = ' seqfile = infil2';
@ARGV = ("/home/shubhi/Desktop/pamlrun/test");
$^I = ".bak"; #safe the old files as file.bak
while (<>) {
s/$find/$replace/g;
print;
}
Also, given the nature of your regex, it looks like you probably want [ ]
(match a space) or \t
(match a tab) not \s
. \s
will match tabs, spaces, and other whitespace characters.
You can also use Tie::File
, but it doesn't seem to provide a backup capability:
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
my $find = qr/\s{6}seqfile\s=\sinfile/;
my $replace = ' seqfile = infil2';
tie my @lines, "Tie::File", "testdata"
or die "could not open file: $!";
for my $line (@lines) {
$line =~ s/$find/$replace/g;
}
Of course, you could roll your own backups with File::Copy
:
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
use File::Copy;
my $find = qr/\s{6}seqfile\s=\sinfile/;
my $replace = ' seqfile = infil2';
copy "testdata", "testdata.bak"
or die "could not backup file: $!";
tie my @lines, "Tie::File", "testdata"
or die "could not open file: $!";
for my $line (@lines) {
$line =~ s/$find/$replace/g;
}
I would also be remiss if I did not point out that this is basically a one-liner:
perl -pi.bak -e 's/\s{6}seqfile\s=\sinfile/ seqfile = infil2/' testdata
This can be shortened further with Perl 5.10 by taking advantage of \K
(zero-width positive look-behind):
perl -pi.bak -e 's/\s{6}seqfile\s=\s\Kinfile/infil2/' testdata
Upvotes: 4
Reputation: 152797
open(FILE, ">filename")
opens the file in replace mode, writing over whatever there was previously.
Also, you cannot have a regexp in the substitution pattern $replace
.
If I understood your intent correctly, this could be replaced with an one-liner
perl -pi -e 's/(\s{6}seqfile\s=\sinfil)e/${1}2/' /home/shubhi/Desktop/pamlrun/test
Upvotes: 7
Reputation: 272217
Your open() is opening a file handle to write to your file. Replace
open (FILE, ">/home/shubhi/Desktop/pamlrun/test") || die "cant open file \n";
with
open (FILE, "/home/shubhi/Desktop/pamlrun/test") || die "cant open file \n";
In the code you've posted, it immediately creates this file for output only. You should open the file, read/process the contents, and then write it out. If the file is sizable, then write to a new file as you read the old one, and replace the old one upon (successful) completion.
Upvotes: 5