Search code examples
perlreplacebulk

How can I do bulk search and replace with Perl?


I have the following script that takes in an input file, output file and replaces the string in the input file with some other string and writes out the output file.

I want to change the script to traverse through a directory of files i.e. instead of prompting for input and output files, the script should take as argument a directory path such as C:\temp\allFilesTobeReplaced\ and search for a string x and replace it with y for all files under that directory path and write out the same files.

How do I do this?

Thanks.

$file=$ARGV[0];

open(INFO,$file);
@lines=<INFO>;
print @lines;

open(INFO,">c:/filelist.txt");

foreach $file (@lines){
   #print "$file\n";
   print INFO "$file";
}

#print "Input file name: ";
#chomp($infilename = <STDIN>);

if ($ARGV[0]){
   $file= $ARGV[0]
}

print "Output file name: ";
chomp($outfilename = <STDIN>);
print "Search string: ";
chomp($search = <STDIN>);
print "Replacement string: ";
chomp($replace = <STDIN>);

open(INFO,$file);
@lines=<INFO>;
open(OUT,">$outfilename") || die "cannot create $outfilename: $!";

foreach $file (@lines){    
    # read a line from file IN into $_
    s/$search/$replace/g; # change the lines
    print OUT $_; # print that line to file OUT
}
close(IN);
close(OUT);

Solution

  • The use of the perl single liner

    perl -pi -e 's/original string/new string/' filename
    

    can be combined with File::Find, to give the following single script (this is a template I use for many such operations).

    use File::Find;
    
    # search for files down a directory hierarchy ('.' taken for this example)
    find(\&wanted, ".");
    
    sub wanted
    {
        if (-f $_)
        {
            # for the files we are interested in call edit_file().
            edit_file($_);
        }
    }
    
    sub edit_file
    {
        my ($filename) = @_;
    
        # you can re-create the one-liner above by localizing @ARGV as the list of
        # files the <> will process, and localizing $^I as the name of the backup file.
        local (@ARGV) = ($filename);
        local($^I) = '.bak';
    
        while (<>)
        {
            s/original string/new string/g;
        }
        continue
        {
            print;
        }
    }