instalar - Necesita perl edición in situ de archivos no en línea de comandos
instalar perl en linux (3)
Tengo un programa que tiene varios nombres de archivos configurados internamente. El programa edita un montón de archivos de configuración asociados con una cuenta de base de datos, y luego cambia la contraseña de la base de datos para la cuenta de la base de datos. La lista de archivos de configuración está asociada con el nombre de la cuenta de la base de datos a través de una lista interna. Cuando proceso estos archivos, tengo el siguiente bucle en mi programa:
BEGIN { $^I = ''.oldPW''; } # Enable in-place editing
...
foreach (@{$Services{$request}{''files''}})
{
my $filename = $Services{$request}{''configDir''} . ''/'' . $_;
print "Processing ${filename}/n";
open CONFIGFILE, ''+<'', $filename or warn $!;
while (<CONFIGFILE>)
{
s/$oldPass/$newPass/;
print;
}
close CONFIGFILE;
}
El problema es que esto escribe la salida modificada en STDOUT, no en CONFIGFILE. ¿Cómo consigo esto para editar realmente en lugar? Mueve el $ ^ I dentro del bucle? imprimir CONFIGFILE? Estoy perplejo.
Actualización: encontré lo que estaba buscando en perlmonks . Puede utilizar un ARGV local dentro del bucle para realizar la edición in situ de la forma normal de Perl. El bucle anterior ahora se ve como:
foreach (@{$Services{$request}{''files''}})
{
my $filename = $Services{$request}{''configDir''} . ''/'' . $_;
print "Processing ${filename}/n";
{
local @ARGV = ( $filename);
while (<>)
{
s/$oldPass/$newPass/;
print;
}
}
}
Si no fuera por pegar el configDir al principio, podría simplemente lanzar toda la lista al @ARGV local, pero esto es lo suficientemente eficiente.
Gracias por las sugerencias útiles sobre Tie :: File, probablemente seguiría así si hago esto de nuevo. Los archivos de configuración que estoy editando nunca tienen más de unos pocos Kbytes de longitud, por lo que un empate no usaría demasiada memoria.
La variable $^I
solo opera en la secuencia de nombres de archivos mantenidos en $ARGV
usando la construcción <>
vacía. Tal vez algo como esto podría funcionar:
BEGIN { $^I = ''.oldPW''; } # Enable in-place editing
...
local @ARGV = map {
$Services{$request}{''configDir''} . ''/'' . $_
} @{$Services{$request}{''files''}};
while (<>) {
s/$oldPass/$newPass/;
# print? print ARGVOUT? I don''t remember
print ARGVOUT;
}
pero si no es un script simple y necesita @ARGV
y STDOUT
para otros propósitos, probablemente sea mejor usar algo como Tie::File
para esta tarea:
use Tie::File;
foreach (@{$Services{$request}{''files''}})
{
my $filename = $Services{$request}{''configDir''} . ''/'' . $_;
# make the backup yourself
system("cp $filename $filename.oldPW"); # also consider File::Copy
my @array;
tie @array, ''Tie::File'', $filename;
# now edit @array
s/$oldPass/$newPass/ for @array;
# untie to trigger rewriting the file
untie @array;
}
Las versiones recientes de File::Slurp
proporcionan funciones prácticas, edit_file
y edit_file_lines
. La parte interna de tu código se vería:
use File::Slurp qw(edit_file);
edit_file { s/$oldPass/$newPass/g } $filename;
Tie :: File ya ha sido mencionado, y es muy simple. Evitar el modificador -i es probablemente una buena idea para los scripts que no pertenecen a la línea de comandos. Si busca evitar Tie :: File, la solución estándar es esta:
- Abra un archivo para la entrada
- Abra un archivo temporal para la salida
- Lea una línea del archivo de entrada.
- Modifica la línea de la forma que quieras.
- Escribe la nueva línea en tu archivo temporal.
- Pasar a la siguiente línea, etc.
- Cerrar los archivos de entrada y salida.
- Cambie el nombre del archivo de entrada a un nombre de copia de seguridad, como agregar .bak al nombre de archivo.
- Cambiar el nombre del archivo de salida temporal al nombre de archivo de entrada original.
Esto es esencialmente lo que sucede detrás de escena con el interruptor -i.bak de todos modos, pero con mayor flexibilidad.