Estoy tratando de implementar una técnica de expansión de parámetros Bash para reemplazar la extensión existente de un archivo en un script Perl.

Este es mi código bash para reemplazar la extensión de archivo que funciona bien:

mv "$f" "${f%.*}.png"

Por otro lado, estoy tratando de usarlo dentro de un script de Perl usando system():

system('mv', "$a/$fileName", "$a/${fileName%.*}".'.png');

$a contiene el nombre del directorio que se pasa a través del argumento de la línea de comandos.

Lanza "syntax error near %" seguido de "missing right curly or square bracket within string". No hay EOF en el mensaje de error.

Cuando no uso %.*, simplemente agrega .png después de que finaliza el archivo existente, pero no lo reemplaza. Alguna ayuda será muy apreciada.

1
Leon S. Kennedy 29 abr. 2020 a las 07:54

3 respuestas

La mejor respuesta

Por lo tanto, desea reemplazar la extensión, para cambiar un nombre de archivo. No hay razón para alcanzar el shell para eso una vez que esté en un script Perl.

El cambio de una extensión se realiza fácilmente "a mano" (consulte a continuación las bibliotecas). Con expresiones regulares

my $new_filename = $filename =~ s/.*\.\K.*/$new_extension/r;

El .* con avidez coincide hasta el último . (que sigue en el patrón), y \K luego elimina todos los partidos para que reemplacemos solo lo que sigue después. O use el ancla de fin de cadena $

my $new_filename = $filename =~ s/\.\K[^.]+$/$new_extension/r;

Qué coincide y reemplaza todos los caracteres que no son . al final de la cadena después de un .. En ambos casos, el modificador /r hace que devuelva la nueva cadena y deje el original sin cambios; sin ella, la cadena ($filename) se cambiaría en el lugar.

Ahora cambie el nombre del archivo en el disco. Una herramienta estándar es Archivo :: Copiar

use File::Copy qw(move);

move $filename, $new_filename  or die "Can't move: $!";

(Si observa el renombrar integrado, mantén la calma y pasa de largo. Es peculiar y " varía enormemente .")


La forma más sólida en general es mediante el uso de bibliotecas adecuadas, por supuesto, y hay otras buenas que se pueden aprovechar para esto. Aquí está con el útil Path :: Tiny (que debe instalar)

use Path::Tiny;

my $path = path($filename);

my $new_fqn = $path->parent->child( $path->basename(qr/[^.]+/) . $new_ext );

Consulte la documentación vinculada para este módulo, pero aquí hay una breve explicación de lo anterior.

El método parent devuelve la ruta hasta el último componente (archivo / directorio), como un objeto Path::Tiny. Luego, el método child invocado le agrega otro componente.

Para eso obtenemos el basename (el último componente, con la extensión despojada en este uso), y luego le agregamos la nueva extensión. Y listo, volvemos al camino completo con la extensión reemplazada. Esto analiza la ruta dos veces, una para parent y otra para basename.

Un beneficio adicional de esto es que el módulo también tiene un método move, así que

$path->move($new_fqn);

Termina el trabajo

El módulo busca errores y croaks o arroja una excepción de su propia clase.


La forma antigua y probada de UNIX es mediante el uso del núcleo File :: Basename

use File::Basename;

my ($name, $path, $ext) = fileparse($filename, qr/\.[^.]*/); 

my $new_fqn = "$path/$name.$new_ext";

Luego use File::Copy::move para cambiar el nombre del archivo.

4
zdim 30 abr. 2020 a las 23:50

No use la sintaxis de Bash y Perl al mismo tiempo, ambos idiomas tienen una sintaxis oscura, usarlos al mismo tiempo empeora las cosas.

Golpetazo:

"${f%.*}.png"

Perl: Use File :: Basename module https://perldoc.perl.org/File/Basename.html

$f_new=fileparse($f_old,qr/\.[^.]*/);
$f_new.=".png";

Golpetazo:

mv

Perl:

rename / File::Copy (see comment)

Juntos (demostración en una línea Perl): para cambiar el nombre de foo.jpg a foo.png

Usando renombrar:

$ perl -MFile::Basename -e '$f_old=$ARGV[0];$f_new=fileparse($f_old,qr/\.[^.]*/);$f_new.=".png";rename $f_old, $f_new' foo.jpg

Usando Archivo :: Copiar

$ perl -MFile::Copy -MFile::Basename -e '$f_old=$ARGV[0];$f_new=fileparse($f_old,qr/\.[^.]*/);$f_new.=".png";File::Copy::move $f_old, $f_new' foo.jpg
1
Boying 29 abr. 2020 a las 07:40

Tiene cadenas entre comillas dobles en Perl, lo que significa que $variables se interpolan dentro de Perl . Es como escribir en Perl

my $xx="abc"
my $yy=${xx%.*}

Obtendría el mismo error.

0
user1934428 29 abr. 2020 a las 07:01