2009-05-27 25 views
6

Tengo la siguiente secuencia de comandos que toma en un archivo de entrada, archivo de salida y reemplaza la cadena en el archivo de entrada con alguna otra cadena y escribe el archivo de salida.¿Cómo puedo hacer una búsqueda masiva y reemplazar con Perl?

Quiero cambiar la secuencia de comandos para recorrer a través de un directorio de archivos es decir, en lugar de solicitar para los archivos de entrada y de salida, el guión debe tomar como argumento una ruta de directorio como C: \ temp \ allFilesTobeReplaced \ y búsqueda para una cadena x y reemplácela con y para todos los archivos bajo esa ruta de directorio y escriba los mismos archivos.

¿Cómo puedo hacer esto?

Gracias.

$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); 

Respuesta

11

El uso de la única liner Perl

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

puede combinarse con File::Find, para dar la siguiente secuencia de comandos simple (esto es una plantilla que uso para muchas de estas operaciones).

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; 
    } 
} 
1

Sé que usted puede usar un simple Per l one-liner desde la línea de comandos, donde nombre de archivo puede ser un nombre de archivo único o una lista de nombres de archivos. Probablemente se podría combinar esto con la respuesta de BGY para obtener el efecto deseado:

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

Y sé que es trillado, pero esto suena mucho como sed, si se puede usar herramientas GNU:

for i in `find ./allFilesTobeReplaced`; do sed -i s/original string/new string/g $i; done 
2

Usted puede hacer esto con el parámetro -i:

Solamente se procesan todos los archivos de forma normal, pero incluyen -i.bak:

#!/usr/bin/perl -i.bak 

while (<>) { 
    s/before/after/; 
    print; 
} 

Esto debe procesar cada archivo, y cambiar el nombre del original a original.bak Y, por supuesto, puede hacerlo como una línea como se menciona por @Jamie Cook

-1

perl -pi -e # OLD # NUEVO # g 'nombre de archivo. Puede reemplazar el nombre de archivo con el patrón que se adapte a su lista de archivos.

Cuestiones relacionadas