Tengo dos archivos en una carpeta en mi Ubuntu 16.04:
a1.dat
b1.DAT
Quiero cambiar el nombre b1.DAT
a b1.dat
para tener los siguientes archivos como resultado en la carpeta:
a1.dat
b1.dat
Intenté (sin éxito):
$ rename *.DAT *.dat
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).
y
$ find . -iname "*.DAT" -exec rename DAT dat '{}' \;
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Buscar esto no resultó en una solución significativa ...
Respuestas:
Parece que ese error proviene de Perl
rename
. Necesita usar comillas, pero solo necesita especificar la parte que desea cambiar, buscar y reemplazar estilo. La sintaxis es así:Eliminar
-n
después de la prueba para cambiar el nombre de los archivos.Para incluir archivos ocultos, cambie la configuración global antes de ejecutar el comando:
Si desea cambiar el nombre de los archivos de forma recursiva, puede usar
o si hay muchas rutas en o debajo del directorio actual que no terminan
.DAT
, será mejor que especifique esas rutas en el segundo comando:Esto será más rápido si sus archivos tienen varios nombres diferentes que no terminan en
.DAT
. [1]Para desactivar estas configuraciones, puede usar
shopt -u
, por ejemploshopt -u globstar
, pero están desactivadas de manera predeterminada y se desactivarán cuando abra un nuevo shell.Si esto resulta en una lista de argumentos excesivamente larga, puede usar, por ejemplo
find
:o mejor
Usar
find ... -exec
con+
es más rápido que usar\;
porque construye una lista de argumentos a partir de los archivos encontrados. Originalmente pensé que no sería posible usarlo, porque mencionó que tenía unargument list too long
problema, pero ahora sé que la lista también se dividirá hábilmente en múltiples invocaciones del comando según sea necesario para evitar ese problema. [2] .Dado
rename
que procesará cada nombre de archivo de la misma manera, no importa qué tan larga sea la lista de argumentos, ya que se puede dividir de forma segura en varias invocaciones. Si el comando con el que está utilizando-exec
no acepta múltiples argumentos o requiere que sus argumentos estén en un orden particular o por cualquier otra razón, dividir la lista de argumentos hará que suceda algo no deseado, puede usarlo\;
, lo que hace que el comando se invoque una vez para cada archivo encontrado (si la lista de argumentos era demasiado larga para otros métodos, ¡esto llevará mucho tiempo!).Muchas gracias a Eliah Kagan por las sugerencias muy útiles para mejorar esta respuesta:
[1] Especificando los nombres de archivo al hacer globbing .
[2]
find ... -exec
con+
divide la lista de argumentos .fuente
-n
cambio de nombre después de la prueba, es solo para mostrar lo que se cambiaráTu puedes hacer:
Descarte
-n
para que tenga lugar el cambio de nombre real.el patrón global
*.DAT
coincide con todos los archivos que terminan.DAT
en el directorio actualen la
rename
sustitución de s,DAT$
partidosDAT
al final\L$&
hace todo el partido en minúsculas;$&
se refiere a todo el partidoSi solo quieres hacer por
b1.DAT
:Ejemplo:
fuente
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ómorename
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 ) alprename
comando. En las versiones más recientes, apunta alfile-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 comorename
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 dicerename
que lo ejecute. Esto se debe a que el primer argumento de la línea de comandos que pasa alrename
comando, que no sean argumentos de opciones como-n
, consiste en un código Perl real . Elrename
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 lugarrename
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 defoo
en la cadena mantenida por la$str
variable abar
, o la deja sin cambios si no contienefoo
. Si solo escribes/foo/bar/
sin usar explícitamente el=~
operador , entonces funciona$_
. Esto quiere decir ques/foo/bar/
es la abreviatura de$_ =~ s/foo/bar/
.Es común para pasar una
s///
expresión derename
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
, elrename
comando nunca vio*.DAT
!Un comando como
rename s/foo/bar/ *.txt
no suele pasar*.txt
como un argumento de línea de comando alrename
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 querename
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 separadosrename
. 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 arename
.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 erab1.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 querename
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?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
oDAT
, de modo que cuando el intérprete Perl ve el códigob1.DAT
, se trata de tratarb1
yDAT
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 queb1.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 scriptsay b1.DAT
Perl al intérprete Perl, que lo ejecuta, imprimiendob1DAT
. (En ese orden, las'
'
cotizaciones cuentan la cáscara de pasarsay b1.DAT
como un solo argumento de línea de comandos, de lo contrario, el espacio podría causarsay
yb1.DAT
que se analiza como palabras separadas yperl
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 escribir
use strict;
en el script de Perl antessay
. Ahora falla con el mismo tipo de error que obtuvo derename
: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 lasubs
restricción. Este comando produce los mismos errores que arriba:Pero generalmente los programadores de Perl simplemente escriben
use strict;
, lo que habilita lasubs
restricción y otras dos.use strict;
Generalmente se recomienda la práctica. Entonces elrename
comando hace esto para su código. Es por eso que recibe ese mensaje de error.4. En resumen, esto es lo que sucedió:
b1.DAT
como el primer argumento de línea de comandos, que serename
trató como un código Perl para ejecutarse en un bucle para cada argumento de nombre de ruta.b1
yDAT
conectado con el.
operador.b1
yDAT
no tenían prefijos con sigilos, por lo que fueron tratados como palabras desnudas.'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.rename
permite a todos restricciones (vars
,refs
ysubs
). 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.
fuente