¿Cómo cambio el nombre de la extensión para un montón de archivos?

480

En un directorio, tengo un montón de *.htmlarchivos. Me gustaría cambiarles el nombre a*.txt

¿Cómo puedo hacer eso? Yo uso el bash shell.

bmw0128
fuente

Respuestas:

382

Para una mejor solución (con solo la funcionalidad bash, a diferencia de las llamadas externas), consulte una de las otras respuestas .


Lo siguiente haría y no requiere que el sistema tenga el renameprograma (aunque lo más frecuente es que tenga esto en un sistema):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

EDITAR: como se señaló en los comentarios, esto no funciona para los nombres de archivo con espacios en ellos sin una cita adecuada (ahora se agregó anteriormente). Cuando trabaje solo en sus propios archivos que sabe que no tienen espacios en los nombres de archivos, esto funcionará, pero siempre que escriba algo que pueda reutilizarse más adelante, no omita las citas adecuadas.

Mikael Auno
fuente
47
Una alternativa, sin nombre de base y con comillas: mv "$ {file}" "$ {file /%. Html / .txt}" (vea man bash, Expansión de parámetros para más detalles)
Rodrigo Queiro
77
Solo es bueno si los archivos están todos en el directorio actual, por supuesto, porque basename elimina la parte del nombre de ruta. ¡Solo un 'cuidado'!
Jonathan Leffler
66
Esta solución es mala, no solo porque es lenta sino porque no funciona con nombres de archivos con espacios en ellos. SIEMPRE debe hacer una cita adecuada en los scripts de bash. mv "$ file" "$ (nombre base" $ file ".html)". txt sería mucho mejor. Pero aún así, mv "$ files" "$ {files% .html} .txt" es mucho mejor.
Balázs Pozsár el
8
en ventanas que acabas de hacerren *.a *.b
Muhammad Umer
2
Como mínimo, utilice la $()sintaxis de retroceso heredada especificada por POSIX en lugar de. Mejora la legibilidad y hace que la sintaxis sea mucho menos ambigua cuando tienes caracteres que necesitarían una barra invertida para que sea literal dentro de la sustitución de comandos con este último.
Charles Duffy
669

Si usa bash, no hay necesidad de comandos externos como sed, basename, rename, expr, etc.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done
ghostdog74
fuente
12
Y si no conoce la extensión de archivo que puede usar "${file%.*}.txt", pero esto podría ser peligroso para los archivos sin extensión.
Jess
1
Nota para cualquiera que tenga problemas para que esto funcione como lo hice yo: ¡observe que no hay $dentro de las llaves!
doug65536
55
Necesito una forma de marcar / marcar esta respuesta como favorita permanentemente, nunca recuerdo la sintaxis exacta y termino buscando en Google
boliva
77
@danip La construcción de signo de porcentaje dentro de paréntesis quita los caracteres del final. También hay una construcción de hash dentro de corchetes que quita los caracteres del principio. Compruébelo: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
44
Otra respuesta de intercambio de Stack (que no puedo encontrar) sugirió esto, pero también usando el --"operador": mv - "$ file" "$ {file% .html} .txt" Ese operador evita los nombres de archivos que comienzan con un '-' de ser analizado por mv como argumentos.
rcreswick
191
rename 's/\.html$/\.txt/' *.html

hace exactamente lo que quieres

Ámbar
fuente
No creo que pueda usar una expresión regular literal en bash como sugiere, ¿qué shell está usando?
DaveR
1
Estoy usando un terminal Mac
bmw0128
Aquí está la página del manual para la versión de renombrar en Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Ámbar
rename es un comando en algunos sistemas. Tengo un script de Perl (originalmente del primer libro de Camel) que hace el trabajo. También hay un programa GNU del mismo nombre que hace aproximadamente el mismo trabajo. Mi Mac no tiene un comando de 'cambio de nombre' proporcionado por el sistema, o no está en mi RUTA (que es moderadamente completa).
Jonathan Leffler
Hay una fórmula de cambio de nombre en Homebrew.
revprez
112

Esto funcionó para mí en OSX de .txt a .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
Steven Lizarazo
fuente
44
Funciona bien en Linux también.
Diziet
Es además el punto, pero para ir de .txta .txt_baksólo hay que concatenar _bak;)
corwin.amber
3
Esto es bueno para renombrar recursivamente
leachryanb
¡Excelente! (bajo Ubuntu 16.04) Mi caso de uso práctico, renombrando todo .scssa .sass(después de la conversión en el lugar ...):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke
2
esto funcionó con +6000 archivos, renombrar informó "la lista de argumentos era demasiado larga"
Tony Cronin
94

Quieres usar rename:

rename -S .html .txt *.html

Esto hace exactamente lo que desea: cambiará la extensión de .htmla .txtpara todos los archivos que coincidan *.html.

Nota: Greg Hewgill señala correctamente que esto no es un bash incorporado; y es un comando separado de Linux. Si solo necesita algo en Linux, esto debería funcionar bien; Si necesita algo más multiplataforma, eche un vistazo a una de las otras respuestas.

DaveR
fuente
77
Aunque esta es una buena solución, el renameprograma no está relacionado bashy tampoco está disponible en todas las plataformas. Solo lo he visto en Linux.
Greg Hewgill el
15
"$ rename .html .txt * .html" genera ... error de sintaxis en (eval 1) línea 1, cerca de "."
Ámbar
8
La sintaxis correcta es lo rename -S .html .text *.htmlque -Srepresenta--subst-all
Marek Sebera
8
cambiar el nombre de instalación
Nick
44
@GregHewgill rename está disponible para Mac OS con HomeBrew
CodeBrauer
36

En una Mac ...

  1. Instale renombrar si no tiene:brew install rename
  2. rename -S .html .txt *.html
izilotti
fuente
15

Para usuarios de Ubuntu:

rename 's/\.html$/\.txt/' *.html
Bheru Lal Lohar
fuente
Esto no es recursivo, pero funcionó para mí en Ubuntu 14.04.
Max Wallace
9

Esta es la solución más ingeniosa que he encontrado que funciona en OSX y Linux, ¡y también funciona muy bien con git!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

y con git:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

bdombro
fuente
8

Aquí hay un ejemplo del comando renombrar:

rename -n s/\.htm$/\.html/’ *.htm

El -n significa que es una prueba de funcionamiento y que en realidad no cambiará ningún archivo. Le mostrará una lista de archivos que cambiarían de nombre si eliminara -n. En el caso anterior, convertirá todos los archivos en el directorio actual de una extensión de archivo de .htm a .html.

Si el resultado de la ejecución de prueba anterior se veía bien, entonces podría ejecutar la versión final:

rename -v s/\.htm$/\.html/’ *.htm

El -v es opcional, pero es una buena idea incluirlo porque es el único registro que tendrá de los cambios que realizó el comando renombrar como se muestra en la salida de muestra a continuación:

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

La parte difícil en el medio es una sustitución de Perl con expresiones regulares, resaltada a continuación:

rename -v s/\.htm$/\.html/’ *.htm
Automóvil club británico
fuente
6

Esta pregunta menciona explícitamente a Bash, pero si tiene ZSH disponible, es bastante simple:

zmv '(*).*' '$1.txt'

Si obtienes zsh: command not found: zmv, simplemente ejecuta:

autoload -U zmv

Y luego inténtalo de nuevo.

Gracias a este artículo original por el consejo sobre zmv.

Michael Leonard
fuente
4

Después del rastreo del sitio web de otra persona, terminé con miles de archivos sin la extensión .html, en un amplio árbol de subdirectorios.

Para cambiarles el nombre a todos de una vez, excepto los archivos que ya tienen una extensión .html (la mayoría de ellos no tenían ninguno), esto funcionó para mí:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

En el caso del OP, podría modificarlo ligeramente, solo para cambiar el nombre de los archivos * .txt, de esta manera:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

Desglosado (hammertime!):

-iname * .txt
: significa considerar SOLAMENTE los archivos que ya terminan en .txt

mv -iv "{}. {txt, html}" - Cuando find pasa a {} como nombre de archivo, $ {filename%. *} extrae su nombre base sin ninguna extensión para formar los parámetros a mv . bash toma el {txt, html} para reescribirlo como dos parámetros para que el comando final se ejecute como:mv -iv "filename.txt" "filename.html"

Corrección necesaria: tratar con espacios en los nombres de archivo

Marcos
fuente
4

El comandommv parece realizar esta tarea de manera muy eficiente en una gran cantidad de archivos (decenas de miles en un segundo). Por ejemplo, para cambiar el nombre de todos los .xmlarchivos a .htmlarchivos, use esto:

mmv ";*.xml" "#1#2.html"

la ;coincidirá con la trayectoria, la *coincidirá con el nombre del archivo, y éstos se conocen como #1y #2en el nombre de reemplazo.

Las respuestas basadas en execo tuberías fueron demasiado lentas o fallaron en una gran cantidad de archivos.

Roko Mijic
fuente
3

Prueba esto

rename .html .txt *.html 

uso:

rename [find] [replace_with] [criteria]
P Sreedhar
fuente
3

Un poco tarde para la fiesta. Podrías hacerlo con xargs:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

O si todos tus archivos están en alguna carpeta

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
especialmente
fuente
3
No. No analicesls . Este comando es ridículo: inútilmente usa un glob con ls, en lugar de usar directamente el glob. Esto se romperá con nombres de archivo que contengan espacios, comillas y (debido a la falta de comillas) caracteres globales.
gniourf_gniourf
Para su información, su artículo vinculado contiene una nota actualizada que dice que los nuevos LS "correctamente" escapan los archivos "si se imprimen en el terminal". Sin embargo, su punto sigue siendo una buena regla general.
Katastic Voyage
3

Esta es una buena manera de modificar múltiples extensiones a la vez:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

Nota: tenga cuidado en que el tamaño de la extensión sea el mismo (el ???)

Nick De Greek
fuente
2

Agradable y simple!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Deano
fuente
2

Si prefiere PERL, hay un breve script PERL (originalmente escrito por Larry Wall, el creador de PERL) que hará exactamente lo que quiere aquí: tips.webdesign10.com/files/rename.pl.txt .

Para su ejemplo, lo siguiente debería hacer el truco:

rename.pl 's/html/txt/' *.html
dudusan
fuente
2
Esta pregunta ya ha sido respondida y aceptada hace mucho tiempo y no parece que su respuesta traiga nada más de lo que ya se dijo.
ChristopheLec
1
+1 ya que era un guión de Larry Wall (modificado por Robin Barker). La última URL disponible es esta: tips.webdesign10.com/files/rename.pl.txt
loretoparisi
1

De manera similar a lo que se sugirió antes, así es como lo hice:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

Primero validado con

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
Carl Bosch
fuente
1

Una línea, sin bucles:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

Ejemplo:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt
Christian Bongiorno
fuente
+1 para mostrar una forma de solo bash que no depende de hacer coincidir exactamente la extensión existente. Esto funciona para cualquier extensión de entrada, ya sea 3 caracteres de largo o 4 caracteres de largo o más
Ciprian Tomoiagă
0

Lamentablemente, no es trivial hacerlo de forma portátil. Probablemente necesites un poco de magia expr.

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

Elimina el eco una vez que estés feliz de que haga lo que quieras.

Editar: basename es probablemente un poco más legible para este caso en particular, aunque expres más flexible en general.

CB Bailey
fuente
Si bien esta puede no ser la mejor respuesta para la pregunta, ¡fue para mí! Necesitaba una forma de renombrar solo en cadena una ruta completa, no solo el nombre del archivo. ¡Gracias por publicar!
donut
0

Esto es lo que solía cambiar el nombre de los .edgearchivos a.blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

Funciona como encanto.

Nixon Kosgei
fuente
0

También puede hacer una función en Bash, agregarla .bashrco algo y luego usarla donde desee.

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

Uso:

change-ext css scss

Fuente del código en función: https://stackoverflow.com/a/1224786/6732111

J Kluseczka
fuente
0

Cambie el nombre de las extensiones de archivo para todos los archivos en el directorio actual y subdirectorios sin ningún otro paquete (solo use script de shell):

  1. Cree un script de shell rename.shen el directorio actual con el siguiente código:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Ejecútalo por ./rename.sh .old .new.

    P.ej. ./rename.sh .html .txt

Neo Liu
fuente