tags:

views:

213

answers:

4

This seems redundant, running perl from a Perl script itself.

my $Pref = "&*())(*&^%$#@!"; 
system("perl -pi -e 's|^SERVERNAME.*\$|SERVERNAME \"\Q$Pref\E\"|g' pserver.prefs");

What is the actual Perl code that will mimic -pi? I just want something that would work like sed on Perl, just as simple as can be.


Based on Todd Gardner's site, it seems it basically just reads and writes all of the file, attempting to apply the regex to every line. The solution was a bit complex for a noob Perl user like me, so I dumbed it down using:

my $ftp = "/home/shared/ftp";
my $backup = $ftp . ".bak";
rename($ftp, $backup);
open (FTP, "<", $backup) or die "Can't open $backup: $!"; 
open (FTP_OUT, ">", $ftp) or die "Can't open $ftp: $!"; 
    while (<FTP>)
    {
     $_ =~ s|$panel_user \Q$panel_oldpass\E |$panel_user \Q$panel_newpass\E |g;
     print FTP_OUT $_;
    }
close(FTP);
close(FTP_OUT);

Is there anything wrong with using two opens? Should this be avoided or is it ok for a simple solution?

I must admit, a system sed command is much more simple and cleaner.

+8  A: 

Check out perlrun which describes the options in detail. In particular, it lays out some options:

From the shell, saying

$ perl -p -i.orig -e "s/foo/bar/; ... "

is the same as using the program:

#!/usr/bin/perl -pi.orig
s/foo/bar/;

which is equivalent to

#!/usr/bin/perl
$extension = '.orig';
LINE: while (<>) {
if ($ARGV ne $oldargv) {
    if ($extension !~ /\*/) {
 $backup = $ARGV . $extension;
    }
    else {
 ($backup = $extension) =~ s/\*/$ARGV/g;
    }
    rename($ARGV, $backup);
    open(ARGVOUT, ">$ARGV");
    select(ARGVOUT);
    $oldargv = $ARGV;
}
s/foo/bar/;
}
continue {
print; # this prints to original filename
}
select(STDOUT);
Todd Gardner
+5  A: 

I'd just use Tie::File.

use Tie::File;
use File::Copy;

copy $file, "$file.bak" or die "Failed to copy $file to $file.bak: $!";
tie @array, "Tie::File", $file or die "Can't open $file: $!";
s/foo/bar/ for @array;
Schwern
A quick note Tie::File became part of core Perl in 5.8. If you are using a version prior to 5.8 either upgrade (please), or you can download Tie::File from CPAN.
Chas. Owens
+3  A: 

Perlmonks has a suggestion equivalent to:

use English qw<$INPLACE_EDIT>;

{
    local ($INPLACE_EDIT, @ARGV) = ('.bak', @files);   
    while (<>) {
        s/this/that/;
        print;       
    }
}

Also recommended in the same thread is Sysadm::Install::pie

Axeman
+4  A: 

B::Deparse is your friend:

cowens@amans:~/test$ perl -MO=Deparse -pi -e 1
BEGIN { $^I = ""; }
LINE: while (defined($_ = <ARGV>)) {
    '???';
}
continue {
    print $_;
}
-e syntax OK

From this we can see that $^I is what implements in-place editing. Just set @ARGV to the files you want to edit, and loop away.

Chas. Owens