Renombrar Ficheros

El comando rename es un estandard Unix que permite renombrar múltiples ficheros. Veamos algunos ejemplos de uso de rename:

rename ’s/\.bak$//’ *.bak
rename ’y/A-Z/a-z/’ *
rename ’s/\.flip$/.flop/’       # rename *.flip to *.flop
rename s/flip/flop/             # rename *flip* to *flop*
rename ’s/^s\.(.*)/$1.X/’    
rename ’s/$/.orig/ */*.[ch]’   
rename ’y/A-Z/a-z/’           
rename ’y/A-Z/a-z/ if -B’       # lo mismo pero con binarios
rename 's{(\d+)}{"-".(2*$1)}e' node*.html

Procesado de los Argumentos

Veamos el procesado de la línea de comandos:

lhp@nereida:~/Lperl/src/cookbook/ch16$ cat -n /usr/bin/rename
 1  #!/usr/bin/perl -w
..  ... # comments
32  use strict;
33
34  use Getopt::Long;
35  Getopt::Long::Configure('bundling');
36
37  my ($verbose, $no_act, $force, $op);
38
39  die "Usage: rename [-v] [-n] [-f] perlexpr [filenames]\n"
40      unless GetOptions(
41          'v|verbose' => \$verbose,
42          'n|no-act'  => \$no_act,
43          'f|force'   => \$force,
44      ) and $op = shift;

El uso de GetOptions significa que podemos llamar al programa de la forma:

$ rename -n 's/1628/chuchu/' node-1628.html
node-1628.html renamed as node-chuchu.html
$ ls -l *chuchu*
ls: *chuchu*: No existe el fichero o el directorio
La opción -n hace que la ejecución sea ''simulada''
$ rename -no 's/1628/chuchu/' node-1628.html
Unknown option: o
Usage: rename [-v] [-n] [-f] perlexpr [filenames]

La llamada Getopt::Long::Configure('bundling')hace que sea posible juntar varias opciones. Por ejemplo, si a, v y x son opciones válidas, entonces un agrupamiento como -vax activa las tres.

Como se ha usado bundling, -no es sinónimo de -n -o. Si se quieren usar prefijos o nombres completos se debe usar el formato largo con dos guiones:

$ rename --no-act 's/1628/chuchu/' node-1628.html
node-1628.html renamed as node-chuchu.html
La presencia de la opción n o de --no-act hace que la variable $no_act se inicia a verdadero.

La función GetOptions retorna falso si se produjo un error procesando la línea de comandos. Los argumentos no procesados, aquellos que no se corresponden a las opciones descritas en la llamada permancen en @ARGV.

Véase la documentación del módulo Getopt::Long para los detalles.

Si $no_act se adopta el modo $verbose:

46  $verbose++ if $no_act;

Si no se proveen ficheros se leen desde STDIN:

48  if (!@ARGV) {
49      print "reading filenames from STDIN\n" if $verbose;
50      @ARGV = <STDIN>;
51      chop(@ARGV);
52  }

Evaluación de la Expresión de Sustitución

El programa pasado como argumento es evaluado en la línea 56. Si contiene errores $@ contendrá el mensaje de error (línea 57).

54  for (@ARGV) {
55      my $was = $_; # viejo nombre del fichero
56      eval $op;     # sustitución efectuada
57      die $@ if $@; # alto si la expresión es inválida
Si el nuevo nombre es igual al viejo no se hacen cambios:
58      next if $was eq $_; # ignore quietly
A menos que se especificara --force no se renombra el fichero si existe ya uno con ese nombre:
59      if (-e $_ and !$force) # existe fichero con el 
60      {                      # nuevo nombre
61          warn  "$was not renamed: $_ already exists\n";
62      }
La evaluación en cortocircuito hace que si se especifico la opción --no-act no se ejecute rename:
63      elsif ($no_act or rename($was, $_)) # Se renombran mediante "rename"
64      {
65          print "$was renamed as $_\n" if $verbose;
66      }
67      else
68      {
69          warn  "Can't rename $was $_: $!\n";
70      }
71  }

Si $no_act es verdadero nunca se evalúa rename($was, $_) y se pasa a ejecutar la línea 65.

El Código

Sigue el código completo:

pp2@europa:~$ sed -ne '32,71p' `which rename` | cat -n
 1  use strict;
 2
 3  use Getopt::Long;
 4  Getopt::Long::Configure('bundling');
 5
 6  my ($verbose, $no_act, $force, $op);
 7
 8  die "Usage: rename [-v] [-n] [-f] perlexpr [filenames]\n"
 9      unless GetOptions(
10          'v|verbose' => \$verbose,
11          'n|no-act'  => \$no_act,
12          'f|force'   => \$force,
13      ) and $op = shift;
14
15  $verbose++ if $no_act;
16
17  if (!@ARGV) {
18      print "reading filenames from STDIN\n" if $verbose;
19      @ARGV = <STDIN>;
20      chop(@ARGV);
21  }
22
23  for (@ARGV) {
24      my $was = $_;
25      eval $op;
26      die $@ if $@;
27      next if $was eq $_; # ignore quietly
28      if (-e $_ and !$force)
29      {
30          warn  "$was not renamed: $_ already exists\n";
31      }
32      elsif ($no_act or rename $was, $_)
33      {
34          print "$was renamed as $_\n" if $verbose;
35      }
36      else
37      {
38          warn  "Can't rename $was $_: $!\n";
39      }
40  }



Subsecciones
Casiano Rodríguez León
2009-10-04