Cambiar el nombre de los archivos de forma recursiva (cambiar la extensión) en Linux

22

¿Cómo cambio el nombre de todos los archivos en un directorio, recursivamente, cambiando una extensión de archivo a otra, para miles de archivos en miles de subcarpetas? Veo muchos comandos que hacen casi lo que quiero, pero no del todo.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile
endolito
fuente
1
¿Tienes Debian renameo Red Hat rename?
Ignacio Vazquez-Abrams
@Ignacio: Ubuntu = Debian?
endolito el
Sí, Ubuntu es un derivado de Debian.
Ignacio Vazquez-Abrams

Respuestas:

23

Lo averigué

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

por supuesto, elimine -v cuando lo haga realmente, o perderá tiempo mostrando todos los archivos

endolito
fuente
14

Algo como:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
Ciro
fuente
este funcionó mejor para mí
cwd
14

Con zsh:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Elimine el -npara realizar el cambio de nombre.

Gilles 'SO- deja de ser malvado'
fuente
1
Fantástica respuesta!
Chris Knadler
4

Encontré que este método es más fácil y más fácil de leer:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

Al menos en las derivaciones de Ubuntu, rename toma una lista de archivos de STDIN si no hay ninguno en la línea de comando. Y esto se puede probar fácilmente con:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

hasta que lo hagas bien.

Bernd Wechner
fuente
1

Renombrar archivos y directorios con find -execdir | rename

Si va a cambiar el nombre de los archivos y directorios no simplemente con un sufijo, entonces este es un buen patrón:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

La -execdiropción impresionante hace un cden el directorio antes de ejecutar el renamecomando, a diferencia de -exec.

-depth asegúrese de que el cambio de nombre ocurra primero en los niños y luego en los padres, para evitar posibles problemas con la falta de directorios principales.

-execdir es necesario porque el cambio de nombre no funciona bien con las rutas de entrada que no son de nombre base, por ejemplo, lo siguiente falla:

rename 's/findme/replaceme/g' acc/acc

El PATHpirateo es obligatorio porque -execdirtiene un inconveniente muy molesto: findes extremadamente obstinado y se niega a hacer nada -execdirsi tiene alguna ruta relativa en su PATHvariable de entorno, por ejemplo ./node_modules/.bin, no:

find: la ruta relativa './node_modules/.bin' se incluye en la variable de entorno PATH, que es insegura en combinación con la acción -execdir de find. Elimina esa entrada de $ PATH

Ver también: /ubuntu/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdires una extensión de búsqueda de GNU para POSIX . renameestá basado en Perl y proviene del renamepaquete. Probado en Ubuntu 18.10.

Cambiar el nombre de la solución alternativa anticipada

Si sus rutas de entrada no provienen find, o si ha tenido suficiente de la molestia relativa de la ruta, podemos usar algunas anticipaciones de Perl para cambiar el nombre de los directorios de manera segura como en:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

No he encontrado un análogo conveniente para -execdircon xargs: Xargs: ¿cambiar el directorio de trabajo a la ruta del archivo antes de ejecutar?

Se sort -rrequiere para garantizar que los archivos vengan después de sus respectivos directorios, ya que las rutas más largas vienen después de las más cortas con el mismo prefijo.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente