Cambiar el nombre de archivos múltiples usando scripts de Bash


27

Quiero cambiar el nombre de varios archivos en el mismo directorio utilizando secuencias de comandos Bash. Los nombres de los archivos son los siguientes:

file2602201409853.p
file0901201437404.p  
file0901201438761.p  
file1003201410069.p  
file2602201410180.p

Quiero cambiar el nombre al siguiente formato:

file2503201409853.p
file2503201437404.p  
file2503201438761.p  
file2503201410069.p  
file2503201410180.p

Estaba leyendo sobre el comando de cambio de nombre e intento hacerlo de esta manera, pero no hace nada, creo que tengo preguntas sobre la sintaxis. Luego leí que puedes hacer un bucle usando el comando mv de la siguiente manera:

for file in cmpsms*2014*.p; do
    mv "$file" "${file/cmpsms*2014*.p/cmpsms25032014*.p}"
done

Pero no puedo cambiar el nombre de los archivos. ¿Qué estoy haciendo mal?



2
No puede tener una expresión de patrón en el lado derecho de una expresión de reemplazo de expansión de parámetros. ¿Qué esperabas estar donde *está eso ?
kojiro

@Kiwy Esa pregunta se trata de eliminar una parte del nombre del archivo. Ergo, muy dudosamente duplicado.
un CVn

2
La próxima vez, describa los cambios de nombre de archivo que desea realizar (tuve que ver esto por un tiempo antes de ver las diferencias y similitudes). Los ejemplos son buenos, pero una descripción , así como ejemplos, es aún mejor.
un CVn

Respuestas:


42

Tenías razón al considerar cambiar el nombre primero. La sintaxis es un poco extraña si no estás acostumbrado a expresiones regulares, pero es, con mucho, la ruta más rápida / más corta una vez que sabes lo que estás haciendo:

rename 's/\d{4}/2503/' file*

Eso simplemente coincide con los primeros 4 números y los intercambia por los que especificó.

Y un arnés de prueba ( -vnsignifica ser detallado pero no hacer nada) usando sus nombres de archivo:

$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p

8
Tenga en cuenta que este es el cambio de nombre de Perl en Debian y derivados (Ubuntu, Mint, ...). En otras distribuciones de Linux, renamees una herramienta de cambio de nombre de archivos completamente diferente (que Debian incluye rename.ul).
Gilles 'SO- deja de ser malvado'

Si su falta distributiva de tal herramienta, mire la respuesta de @Michael Campbell. Creo que cada reemplazo distributivo reemplaza renameal de Debian
Astery

25

Esto debería funcionar:

for f in file*; do mv $f ${f/${f:4:8}/25032014}; done

Reemplaza la cadena entre el 4 ° y el 12 ° carácter con "25032014".


Esto for f in file*; do mv $f ${f/${f:4:4}/2503}; donetambién funciona.
Avinash Raj

Eso es bueno. Si solo quiere hacer un reemplazo regular de palabra por palabra, funciona como sed. por ejemplofor f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Eric

1
@Eric: publiqué tu respuesta como alternativa porque creo que es más clara y elegante. Si también quieres publicarlo como respuesta, eliminaré el mío. ¡Gracias!
Yehosef


Me da un error: "mv: target 'FILE_NAME' no es un directorio"
Aubrey

10

Esta es realmente la respuesta de @ Eric desde arriba, pero es una respuesta elegante, así que la vuelvo a publicar como una respuesta adecuada para llamar más la atención.

for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done

1
ptrn='file[0-9][0-9][0-9][0-9]2014[0-9][0-9][0-9][0-9][0-9].p'
path=/dir
( set -- "${path}/"${ptrn} ; for f ; do {
    echo "mv ${path}/${f} \
        ${path}/file25032014${f#2014}" 
} ; done )

Esto debería funcionar. Nota: no tengo la costumbre de entregar comandos masivos de mv, como está escrito es solo un eco. Tendrás que resolver eso antes de que funcione.


1

Una forma nativa simple de hacerlo sin bucles, con recorrido de directorio :

find -type f | xargs -I {} mv {} {}.txt

Cambiará el nombre de cada archivo en su lugar.

Y a continuación un ejemplo de trabajo con paralelización :

find -name "file*.p" | parallel 'f="{}" ; mv -- {} ${f:0:4}2503${f:8}'

Fue un primer acercamiento fácil imaginar una mejor solución. Si desea un comando de trabajo, haga lo siguiente:
dtrckd

find -type f -name "file*.p" | parallel 'ext="{}" ; mv -- {} ${ext:0:4}2503${ext:8}'
dtrckd

0

Si descubres que haces mucho este tipo de cosas, busca "rename.pl". Es un script perl, pero le permite simplemente alimentarlo con código perl (como /// expresión), y hará un cambio de nombre en masa basado en esa expresión o código.

Hay una versión básica aquí: http://stackoverflow.org/wiki/Rename.pl pero hay otras versiones flotando en la red. Ha existido por siglos y siglos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.