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?

franvergara66
fuente
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
Oli
fuente
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".

caos
fuente
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
¿Por qué faltan las comillas dobles ?
Comodín el
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
Yehosef
fuente
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.

mikeserv
fuente
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}'
dtrckd
fuente
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.

Michael Campbell
fuente