Search code examples
perlsearchcommand-linereplacebulk

Is there a simple way to do bulk file text substitution in place?


I've been trying to code a Perl script to substitute some text on all source files of my project. I'm in need of something like:

perl -p -i.bak -e "s/thisgoesout/thisgoesin/gi" *.{cs,aspx,ascx}

But that parses all the files of a directory recursively.

I just started a script:

use File::Find::Rule;
use strict;

my @files = (File::Find::Rule->file()->name('*.cs','*.aspx','*.ascx')->in('.'));

foreach my $f (@files){
    if ($f =~ s/thisgoesout/thisgoesin/gi) {
           # In-place file editing, or something like that
    }
}

But now I'm stuck. Is there a simple way to edit all files in place using Perl?

Please note that I don't need to keep a copy of every modified file; I'm have 'em all subversioned =)

Update: I tried this on Cygwin,

perl -p -i.bak -e "s/thisgoesout/thisgoesin/gi" {*,*/*,*/*/*}.{cs,aspx,ascx

But it looks like my arguments list exploded to the maximum size allowed. In fact, I'm getting very strange errors on Cygwin...


Solution

  • If you assign @ARGV before using *ARGV (aka the diamond <>), $^I/-i will work on those files instead of what was specified on the command line.

    use File::Find::Rule;
    use strict;
    
    @ARGV = (File::Find::Rule->file()->name('*.cs', '*.aspx', '*.ascx')->in('.'));
    $^I = '.bak';  # or set `-i` in the #! line or on the command-line
    
    while (<>) {
        s/thisgoesout/thisgoesin/gi;
        print;
    }
    

    This should do exactly what you want.

    If your pattern can span multiple lines, add in a undef $/; before the <> so that Perl operates on a whole file at a time instead of line-by-line.