Necesito cambiar el nombre de aprox. 70,000 archivos. Por ejemplo: de sb_606_HBO_DPM_0089000
a sb_606_dpm_0089000
etc.
El rango de números va de 0089000
a 0163022
. Es solo la primera parte del nombre que necesita cambiar. Todos los archivos están en un solo directorio y están numerados secuencialmente (una secuencia de imágenes). Los números deben permanecer sin cambios.
Cuando intento esto en bash, me sorprende que la "Lista de argumentos sea demasiado larga".
Editar:
Primero intenté renombrar un solo archivo con mv
:
mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx
Luego intenté renombrar un rango (aprendí aquí la semana pasada cómo mover una carga de archivos, así que pensé que la misma sintaxis podría funcionar para renombrar los archivos ...). Yo creo que probé el siguiente (o algo parecido):
mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx
ARG_MAX
límite del shell . Como esta pregunta solicita explícitamente una solución de línea de comandos, las soluciones GUI (posiblemente iguales) como en la otra pregunta tampoco coinciden.mv {1..2} {3..4}
no funciona, lo cual es un problema completamente diferente deARG_MAX
... ¡Todos los que respondieron probablemente sentirán lo mismo! Por lo tanto, desde mi punto de vista, desearía que revierta su última edición y, si lo desea, haga una pregunta completamente nueva acerca demv
los rangosargument list too long
error. No hay necesidad de aclarar más, esto claramente no es una trampa ya que necesitamos una solución alternativa para tratar con ARG_MAX y las respuestas en el duplicado propuesto no lo hacen.Respuestas:
Una forma es usar
find
con-exec
, y la+
opción. Esto construye una lista de argumentos, pero divide la lista en tantas llamadas como sea necesario para operar en todos los archivos sin exceder la lista máxima de argumentos. Es adecuado cuando todos los argumentos serán tratados de la misma manera. Este es el caso conrename
, aunque no conmv
.Es posible que deba instalar Perl rename:
Entonces puedes usar, por ejemplo:
Eliminar
-n
después de la prueba, para cambiar el nombre de los archivos.fuente
Voy a sugerir tres alternativas. Cada uno es un comando simple de una sola línea, pero proporcionaré variantes para casos más complicados, principalmente en el caso de que los archivos a procesar se mezclen con otros archivos en el mismo directorio.
mmv
Me gustaría usar el comando MMV del paquete del mismo nombre :
Tenga en cuenta que los argumentos se pasan como cadenas, por lo que la expansión global no se produce en el shell. El comando recibe exactamente dos argumentos y luego encuentra los archivos correspondientes internamente, sin límites estrictos en la cantidad de archivos. También tenga en cuenta que el comando anterior asume que todos los archivos que coincidan con el primer glob serán renombrados. Por supuesto, eres libre de ser más específico:
Si tiene archivos fuera del rango de números solicitados en el mismo directorio, podría ser mejor con el ciclo sobre los números que figuran más adelante en esta respuesta. Sin embargo, también podría usar una secuencia de invocaciones de mmv con patrones adecuados:
recorrer los números
Si desea evitar instalar cualquier cosa, o necesita seleccionar por rango de números evitando coincidencias fuera de este rango, y está preparado para esperar 74,023 invocaciones de comandos, puede usar un bucle bash simple:
Esto funciona particularmente bien aquí ya que no hay espacios en la secuencia. De lo contrario, es posible que desee verificar si el archivo fuente realmente existe.
Tenga en cuenta que, en contraste con
for ((i=89000; i<=163022; ++i))
la expansión de llaves, maneja los ceros iniciales desde que se lanzó Bash hace un par de años. En realidad, solicité un cambio, así que estoy feliz de ver casos de uso.Lecturas adicionales: Expansión de llaves en las páginas de información de Bash, particularmente la parte sobre
{x..y[..incr]}
.recorrer los archivos
Otra opción sería recorrer un globo adecuado, en lugar de simplemente recorrer el rango entero en cuestión. Algo como esto:
Nuevamente, esta es una
mv
invocación por archivo. Y de nuevo, el ciclo está sobre una larga lista de elementos, pero la lista completa no se pasa como argumento a un subproceso, sino que se maneja internamente por bash, por lo que el límite no le causará problemas.Lectura adicional: Expansión de parámetros de Shell en las páginas de información de Bash, documentando
${parameter/pattern/string}
entre otros.Si desea restringir el rango de números al que proporcionó, puede agregar un cheque para eso:
Aquí
${i##pattern}
elimina la coincidencia de prefijo más largapattern
de$i
. El prefijo más largo se define como cualquier cosa, luego un guión bajo, luego cero o más ceros. Este último se escribe como*(0)
un patrón de globo extendido que depende de laextglob
opción que se configure. Eliminar los ceros a la izquierda es importante para tratar el número como base 10 y no como base 8. El+([0-9])
argumento en el bucle es otro globo extendido, que coincide con uno o más dígitos, en caso de que tenga archivos allí que comiencen igual pero no terminen en un número.fuente
Una forma de evitar el
ARG_MAX
límite es usar el basil shell de bashprintf
:Ex.
pero
fuente
find
en el directorio actual.
para todos los archivos-type f
y hacer cambiar el nombre del archivo que se encuentra$1
con el reemplazoHBO_DPM
dedmp
uno por uno-exec ... \;
reemplace
echo
conmv
para realizar el cambio de nombre.fuente
Podrías escribir un pequeño script de Python, algo como:
Guarde eso como un archivo de texto como
rename.py
en la carpeta en la que están los archivos, luego con el terminal en esa carpeta vaya:fuente
Puede hacerlo archivo por archivo (puede llevar algo de tiempo) con
Al igual que el Perl
rename
usado en otras respuestas,rename.ul
también tiene una opción-n
o--no-act
para probar.fuente
-n
bandera que usé para probar y sugirió que también se puede usarrename.ul
.Veo que nadie ha invitado a mi mejor amigo
sed
a la fiesta :). El siguientefor
ciclo logrará su objetivo:Hay muchas herramientas para tal trabajo, seleccione la que sea más comprensible para usted. Este es simple y fácil de modificar para adaptarse a este u otros propósitos ...
fuente
$i
en la sustitución de comandos, pero no hay una manera fácil de manejar una nueva línea final en el nombre del archivo.Dado que estamos dando opciones, aquí hay un enfoque de Perl.
cd
en el directorio de destino y ejecute:Explicación
perl -e
: ejecuta el script dado por-e
.foreach(glob){}
: ejecuta lo que esté en{ }
cada resultado del globo.glob("sb_*")
: devuelve una lista de todos los archivos y directorios en el directorio actual cuyos nombres coinciden con el shell globsb*
.rename $_, s/_HBO_DPM_/_dpm_/r
: perl magic.$_
es una variable especial que contiene cada elemento sobre el que estamos iterando (en elforeach
). Entonces, aquí, se encontrará cada archivo.s/_HBO_DPM_/_dpm_/
reemplaza la primera aparición de_HBO_DPM_
con_dpm_
. Se ejecuta$_
de manera predeterminada, por lo que se ejecutará en cada nombre de archivo. El/r
medio "aplica este reemplazo a una copia de la cadena de destino (el nombre del archivo) y devuelve la cadena modificada.rename
Hace lo que esperaría: cambia el nombre de los archivos. Así que todo cambiará el nombre del archivo actual ($_
) a sí mismo con_HBO_DPM_
reemplazado por_dpm_
.Podría escribir lo mismo que un script expandido (y más legible):
fuente
Dependiendo del tipo de cambio de nombre que esté imaginando, usar vidir con edición de líneas múltiples puede ser satisfactorio.
En su caso particular, puede seleccionar todas las líneas en su editor de texto y eliminar la parte _ " HBO" de los nombres de archivo con pocas teclas.
fuente
vidir
?