Otras respuestas han abordado uno de los dos aspectos principales de esta pregunta: el de cómo llevar a cabo con éxito la operación de cambio de nombre que necesitaba. El propósito de esta respuesta es explicar por qué sus comandos no funcionaron, incluido el significado de ese extraño mensaje de error "no se permite la palabra básica" en el contexto del rename
comando.
La primera sección de esta respuesta trata sobre la relación entre rename
Perl y cómo rename
utiliza el primer argumento de línea de comando que le pasa, que es su argumento de código. La segunda sección trata sobre cómo el shell realiza expansiones, específicamente globbing, para construir una lista de argumentos. La tercera sección trata sobre lo que está sucediendo en el código Perl que proporciona errores de "Bareword no permitido". Finalmente, la cuarta sección es un resumen de todos los pasos que se realizan entre ingresar el comando y obtener el error.
1. Cuando rename
reciba mensajes de error extraños, agregue "Perl" a su búsqueda.
En Debian y Ubuntu, el rename
comando es un script de Perl que realiza el cambio de nombre de archivo. En versiones anteriores, incluido 14.04 LTS, que todavía se admite a partir de este escrito, era un enlace simbólico que apuntaba ( indirectamente ) al prename
comando. En las versiones más recientes, apunta al file-rename
comando más nuevo . Esos dos comandos de cambio de nombre de Perl funcionan principalmente de la misma manera, y solo me referiré a ambos como rename
al resto de esta respuesta.
Cuando usa el rename
comando, no solo está ejecutando el código Perl que otra persona ha escrito. También está escribiendo su propio código Perl y le dice rename
que lo ejecute. Esto se debe a que el primer argumento de la línea de comandos que pasa al rename
comando, que no sean argumentos de opciones como -n
, consiste en un código Perl real . El rename
comando usa este código para operar en cada uno de los nombres de ruta que le pasa como argumentos de línea de comando posteriores. (Si no pasa ningún argumento de nombre de ruta, en su lugar rename
lee los nombres de ruta de la entrada estándar , uno por línea).
El código se ejecuta dentro de un bucle , que itera una vez por nombre de ruta. En la parte superior de cada iteración del bucle, antes de que se ejecute su código, a la $_
variable especial se le asigna el nombre de ruta que se está procesando actualmente. Si su código hace que el valor de $_
se cambie a otra cosa, entonces se cambia el nombre de ese archivo para que tenga el nuevo nombre.
Muchas expresiones en Perl operan implícitamente en la $_
variable cuando no se les da ninguna otra expresión para usar como operando . Por ejemplo, la expresión de sustitución $str =~ s/foo/bar/
cambia la primera aparición de foo
en la cadena mantenida por la $str
variable a bar
, o la deja sin cambios si no contiene foo
. Si solo escribe s/foo/bar/
sin usar explícitamente el =~
operador , entonces funciona $_
. Esto quiere decir que s/foo/bar/
es la abreviatura de $_ =~ s/foo/bar/
.
Es común para pasar una s///
expresión de rename
que el argumento de código (es decir, el primer argumento de línea de comandos), pero no tiene que hacerlo. Puede darle cualquier código Perl que desee que se ejecute dentro del bucle, para examinar cada valor $_
y (condicionalmente) modificarlo.
Esto tiene muchas consecuencias interesantes y útiles , pero la gran mayoría de ellas están más allá del alcance de esta pregunta y respuesta. La razón principal por la que traigo esto aquí, de hecho, la razón principal por la que decidí publicar esta respuesta, es para señalar que, debido a que el primer argumento rename
es en realidad el código Perl, cada vez que recibe un mensaje de error extraño y usted Si tiene problemas para encontrar información al buscar, puede agregar "Perl" a la cadena de búsqueda (o incluso reemplazar "cambiar el nombre" por "Perl", a veces) y con frecuencia encontrará una respuesta.
2. Con rename *.DAT *.dat
, el rename
comando nunca vio *.DAT
!
Un comando como rename s/foo/bar/ *.txt
no suele pasar *.txt
como un argumento de línea de comando al rename
programa, y usted no quiere que lo haga, a menos que tenga un archivo cuyo nombre sea literalmente *.txt
, que con suerte no lo hará.
rename
no interpreta patrones globales como *.txt
, *.DAT
, *.dat
, x*
, *y
, o *
cuando se le pasa como argumento de nombre de ruta. En cambio, su shell realiza la expansión del nombre de ruta en ellos (que también se llama expansión de nombre de archivo, y también llamada globalización). Esto sucede antes de que rename
se ejecute la utilidad. El shell expande los globos en nombres de ruta potencialmente múltiples y los pasa a todos, como argumentos de línea de comandos separados rename
. En Ubuntu, su shell interactivo es Bash , a menos que lo haya cambiado, razón por la cual me he vinculado al manual de referencia de Bash anterior.
Hay una situación en la que se puede pasar un patrón global como un único argumento de línea de comandos sin expandir a rename
: cuando no coincide con ningún archivo. Diferentes shells exhiben un comportamiento predeterminado diferente en esta situación, pero el comportamiento predeterminado de Bash es simplemente pasar el glob literalmente. Sin embargo, ¡raramente quieres esto! Si lo deseaba, debe asegurarse de que el patrón no se expande, citandolo . Esto sirve para pasar argumentos a cualquier comando, no solo a rename
.
Las citas no son solo para globbing (expansión de nombre de archivo), porque hay otras expansiones que su shell realiza en texto sin comillas y, para algunas de ellas pero no para otras , también en texto entre "
"
comillas. En general, cada vez que desee pasar un argumento que contenga caracteres que pueden ser tratados especialmente por el shell, incluidos los espacios, debe citarlo, preferiblemente con '
'
comillas .
El código Perl s/foo/bar/
no contiene nada tratado especialmente por el shell, pero habría sido una buena idea para mí haberlo citado también, y escrito 's/foo/bar/'
. (De hecho, la única razón por la que no era que iba a ser confuso para algunos lectores, ya que todavía no había hablado de citar.) La razón por la que digo esto habría sido bueno es porque es muy común que el código Perl no contiene tales caracteres, y si tuviera que cambiar ese código, podría no recordar comprobar si era necesario citar. Por el contrario, si desea que la carcasa se expanda un pegote, debe no ser citado.
3. Lo que el intérprete de Perl quiere decir con "palabra no permitida"
Los mensajes de error que mostró en su pregunta revelan que, cuando ejecutó rename *.DAT *.dat
, su shell se expandió *.DAT
en una lista de uno o más nombres de archivo, y que el primero de esos nombres era b1.DAT
. Todos los argumentos subsiguientes, tanto los demás expandidos *.DAT
como los que se expandieron desde, *.dat
surgieron después de ese argumento, por lo que habrían sido interpretados como nombres de ruta.
Debido a que lo que realmente funcionó fue algo así rename b1.DAT ...
, y debido a que rename
trata su primer argumento sin opción como código Perl, la pregunta es: ¿por qué b1.DAT
produce estos errores de "no se permite la palabra pura" cuando lo ejecuta como código Perl?
Bareword "b1" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
En un shell, citamos nuestras cadenas para protegerlas de expansiones de shell no intencionadas que de otro modo las transformarían en otras cadenas automáticamente (consulte la sección anterior). Los shells son lenguajes de programación de propósito especial que funcionan de manera muy diferente a los lenguajes de propósito general (y su sintaxis y semántica muy extrañas lo reflejan). Pero Perl es un lenguaje de programación de propósito general y, como la mayoría de los lenguajes de programación de propósito general, el propósito principal de las citas en Perl no es proteger las cadenas, sino mencionarlas. Esta es en realidad una forma en que la mayoría de los lenguajes de programación son similares al lenguaje natural. En inglés, y suponiendo que tenga un perro, "su perro" es una frase de dos palabras, mientras que su perro es un perro. Del mismo modo, en Perl, '$foo'
es una cadena, mientras que $foo
es algo cuyo nombre es $foo
.
Sin embargo, a diferencia de casi cualquier otro lenguaje de programación de propósito general, Perl también a veces interpretar el texto no indicada como mencionar una cadena - una cadena que es la "misma", ya que, en el sentido de que está compuesto por los mismos caracteres en El mismo orden. Solo intentará interpretar el código de esa manera si es una palabra simple (sin $
u otro sigilo, ver más abajo), y después no pudo encontrar ningún otro significado para darle. Luego lo tomará como una cadena, a menos que le diga que no lo haga habilitando restricciones .
Las variables en Perl generalmente comienzan con un carácter de puntuación llamado sigilo , que especifica el tipo amplio de la variable. Por ejemplo, $
significa escalar , @
significa matriz y %
significa hash . ( Hay otros ) . No se preocupe si lo encuentra confuso (o aburrido), porque solo lo menciono para decir que cuando aparece un nombre válido en un programa Perl pero no está precedido por un sigilo, ese nombre se dice que es una palabra desnuda .
Las palabras desnudas sirven para varios propósitos, pero generalmente significan una función incorporada o una subrutina definida por el usuario que se ha definido en el programa (o en un módulo utilizado por el programa). Perl no se ha incorporado en las funciones llamadas b1
o DAT
, de modo que cuando el intérprete Perl ve el código b1.DAT
, se trata de tratar b1
y DAT
como los nombres de subrutinas. Suponiendo que no se hayan definido tales subrutinas, esto falla. Luego, siempre que no se hayan habilitado las restricciones , las trata como cadenas. Esto funcionará, aunque nadie sabe si realmente pretendía que esto sucediera o no . El .
operador de Perl concatena cadenas , por lo que b1.DAT
evalúa la cadenab1DAT
. Es decir, b1.DAT
es una mala forma de escribir algo como 'b1' . 'DAT'
o "b1" . "DAT"
.
Puede probar esto usted mismo ejecutando el comando perl -E 'say b1.DAT'
, que pasa el breve script say b1.DAT
Perl al intérprete Perl, que lo ejecuta, imprimiendo b1DAT
. (En ese orden, las '
'
cotizaciones cuentan la cáscara de pasar say b1.DAT
como un solo argumento de línea de comandos, de lo contrario, el espacio podría causar say
y b1.DAT
que se analiza como palabras separadas y perl
los recibiría como argumentos separados. perl
No no ver las cotizaciones a sí mismos, como el la cáscara los elimina )
Pero ahora, intente escribiruse strict;
en el script de Perl antes say
. Ahora falla con el mismo tipo de error que obtuvo de rename
:
$ perl -E 'use strict; say b1.DAT'
Bareword "b1" not allowed while "strict subs" in use at -e line 1.
Bareword "DAT" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
Esto sucedió porque use strict;
prohibió al intérprete de Perl tratar las palabras desnudas como cadenas. Para prohibir esta característica particular, realmente sería suficiente habilitar solo la subs
restricción. Este comando produce los mismos errores que arriba:
perl -E 'use strict "subs"; say b1.DAT'
Pero generalmente los programadores de Perl simplemente escriben use strict;
, lo que habilita la subs
restricción y otras dos. use strict;
Generalmente se recomienda la práctica. Entonces el rename
comando hace esto para su código. Es por eso que recibe ese mensaje de error.
4. En resumen, esto es lo que sucedió:
- Su shell pasó
b1.DAT
como el primer argumento de línea de comandos, que se rename
trató como un código Perl para ejecutarse en un bucle para cada argumento de nombre de ruta.
- Esto fue tomado en el sentido
b1
y DAT
conectado con el .
operador.
b1
y DAT
no tenían prefijos con sigilos, por lo que fueron tratados como palabras desnudas.
- Esas dos palabras simples se habrían tomado como nombres de funciones integradas o cualquier subrutina definida por el usuario, pero nada de eso tenía ninguno de esos nombres.
- Si los "subs estrictos" no hubieran sido habilitados, entonces habrían sido tratados como las expresiones de cadena
'b1'
y 'DAT
'y concatenados. Eso está lejos de lo que pretendía, lo que ilustra cómo esta característica a menudo no es útil.
- Pero "estrictas" submarinos se habilitó, porque
rename
permite a todos restricciones ( vars
, refs
y subs
). Por lo tanto, recibió un error en su lugar.
rename
Salir debido a este error. Debido a que este tipo de error ocurrió antes, no se realizaron intentos de cambio de nombre de archivo, aunque no lo haya aprobado -n
. Esto es algo bueno, que a menudo protege a los usuarios de cambios involuntarios de nombre de archivo y, en ocasiones, incluso de la pérdida real de datos.
Gracias a Zanna , quien me ayudó a abordar varias deficiencias importantes en un borrador anterior de esta respuesta . Sin ella, esta respuesta habría tenido menos sentido y podría no publicarse en absoluto.