Cambiar la extensión de cien fotos, quitar los espacios de los nombres o numerar una carpeta entera son tareas de un bucle de Bash. Aquí tienes cada caso con el resultado real, la expansión de parámetros que hace el trabajo y las tres precauciones que evitan perder archivos: ensayar antes, no sobrescribir y cuidar los comodines que no encuentran nada.
También te puede interesar
Todos los ejemplos parten de esta carpeta, fotos, con nombres mezclados en mayúsculas, con espacios y con varias extensiones para la misma cosa (cada script empieza con cd fotos || exit 1, para no renombrar nada en otra carpeta si el cd fallara):
terminal$ ls -1 fotos IMG_0001.JPG IMG_0002.JPG IMG_0003.jpeg Informe Final.TXT Presupuesto 2026.ods notas de la reunión.txt
Primero, el ensayo
Renombrar en lote es de las pocas operaciones que se hacen en un segundo y se deshacen en una tarde. La costumbre más útil es escribir el bucle con echo delante de mv: así ves cada orden que se ejecutaría, y cuando todo está bien quitas el echo:
#!/usr/bin/env bash
cd fotos || exit 1
echo "Ensayo:"
for archivo in *.JPG; do
echo mv -- "$archivo" "${archivo%.JPG}.jpg"
done
echo "De verdad:"
for archivo in *.JPG; do
mv -n -- "$archivo" "${archivo%.JPG}.jpg"
done
ls -1salidaEnsayo: mv -- IMG_0001.JPG IMG_0001.jpg mv -- IMG_0002.JPG IMG_0002.jpg De verdad: IMG_0001.jpg IMG_0002.jpg IMG_0003.jpeg Informe Final.TXT Presupuesto 2026.ods notas de la reunión.txt
${archivo%.JPG} quita .JPG del final del nombre y deja el resto, al que se le pega la extensión nueva. Las comillas alrededor de cada nombre son obligatorias: sin ellas, Informe Final.TXT llegaría a mv como dos argumentos. El -n de mv impide sobrescribir un archivo que ya exista, y -- evita que un nombre que empiece por guion se tome por una opción.
Quitar espacios
#!/usr/bin/env bash
cd fotos || exit 1
for archivo in *' '*; do
nuevo=${archivo// /_}
mv -n -- "$archivo" "$nuevo"
done
ls -1salidaIMG_0001.JPG IMG_0002.JPG IMG_0003.jpeg Informe_Final.TXT Presupuesto_2026.ods notas_de_la_reunión.txt
${archivo// /_} sustituye todos los espacios por guiones bajos; con una sola barra, ${archivo/ /_}, cambiaría solo el primero. El comodín *' '* elige únicamente los nombres que tienen al menos un espacio.
Todo a minúsculas
#!/usr/bin/env bash
cd fotos || exit 1
for archivo in *; do
nuevo=${archivo,,}
if [[ $archivo == "$nuevo" ]]; then
continue
fi
if [[ -e $nuevo ]]; then
echo "Ya existe «$nuevo», no toco «$archivo»"
continue
fi
mv -- "$archivo" "$nuevo"
done
ls -1salidaimg_0001.jpg img_0002.jpg img_0003.jpeg informe final.txt notas de la reunión.txt presupuesto 2026.ods
${archivo,,} pasa el nombre a minúsculas (y ${archivo^^}, a mayúsculas), incluidas las letras con tilde. Esta sintaxis llegó en Bash 4: en el Bash 3.2 de macOS da un error, y allí hay que usar tr '[:upper:]' '[:lower:]', que no siempre trata bien los caracteres acentuados. Comprobar antes si el destino existe importa más de lo que parece: en macOS y Windows el sistema de archivos no distingue mayúsculas de minúsculas, y IMG.JPG e img.jpg son el mismo archivo.
Numerar
#!/usr/bin/env bash
cd fotos || exit 1
n=1
for archivo in IMG_*.JPG IMG_*.jpeg; do
extension=${archivo##*.}
extension=${extension,,}
if [[ $extension == jpeg ]]; then
extension=jpg
fi
printf -v nuevo 'vacaciones_%03d.%s' "$n" "$extension"
mv -n -- "$archivo" "$nuevo"
n=$((n + 1))
done
ls -1salidaInforme Final.TXT Presupuesto 2026.ods notas de la reunión.txt vacaciones_001.jpg vacaciones_002.jpg vacaciones_003.jpg
printf -v nuevo guarda el resultado en la variable en vez de imprimirlo, y %03d rellena con ceros hasta tres cifras, para que los archivos se ordenen bien: vacaciones_010 va detrás de vacaciones_009, mientras que vacaciones_10 iría delante de vacaciones_9. ${archivo##*.} se queda con lo que hay detrás del último punto, es decir, la extensión.
Cuidado con los comodines que no encuentran nada
#!/usr/bin/env bash
cd fotos || exit 1
for archivo in *.png; do
echo "Renombraría: $archivo"
done
shopt -s nullglob
for archivo in *.png; do
echo "Con nullglob: $archivo"
done
echo "Fin"salidaRenombraría: *.png Fin
Si un comodín no encuentra ningún archivo, Bash lo deja tal cual, y el bucle da una vuelta con el texto literal *.png: un mv ahí fallaría o, peor, crearía un archivo con ese nombre. Con shopt -s nullglob, un comodín sin coincidencias desaparece y el bucle no se ejecuta.
Un script reutilizable, con modo de ensayo
#!/usr/bin/env bash
# Uso: renombrar.sh [-n] CARPETA EXTENSIÓN_VIEJA EXTENSIÓN_NUEVA
# Cambia la extensión de los archivos de CARPETA. Con -n solo muestra lo que haría.
ensayo=0
if [[ ${1:-} == -n ]]; then
ensayo=1
shift
fi
if (( $# != 3 )); then
echo "Uso: ${0##*/} [-n] CARPETA EXTENSIÓN_VIEJA EXTENSIÓN_NUEVA" >&2
exit 2
fi
cd -- "$1" || exit 1
vieja=$2
nueva=$3
shopt -s nullglob
archivos=(*."$vieja")
if (( ${#archivos[@]} == 0 )); then
echo "No hay archivos *.$vieja" >&2
exit 1
fi
errores=0
for archivo in "${archivos[@]}"; do
destino=${archivo%."$vieja"}.$nueva
if [[ -e $destino ]]; then
echo "Me salto «$archivo»: ya existe «$destino»" >&2
errores=$((errores + 1))
continue
fi
if (( ensayo )); then
echo "Renombraría «$archivo» -> «$destino»"
else
mv -n -- "$archivo" "$destino" && echo "«$archivo» -> «$destino»"
fi
done
if (( errores > 0 )); then
exit 1
fisalidaRenombraría «IMG_0001.JPG» -> «IMG_0001.jpg» Renombraría «IMG_0002.JPG» -> «IMG_0002.jpg»
Con -n solo enseña lo que haría. Sin él, y en una carpeta donde ya existe IMG_0002.jpg, renombra lo que puede, se salta el conflicto y termina con código 1 para que quien lo llame sepa que algo quedó pendiente:
terminal$ ls -1 fotos IMG_0001.JPG IMG_0002.JPG IMG_0002.jpg IMG_0003.jpeg Informe Final.TXT Presupuesto 2026.ods notas de la reunión.txt $ bash renombrar.sh fotos JPG jpg; echo "código: $?" «IMG_0001.JPG» -> «IMG_0001.jpg» Me salto «IMG_0002.JPG»: ya existe «IMG_0002.jpg» código: 1 $ ls -1 fotos IMG_0001.jpg IMG_0002.JPG IMG_0002.jpg IMG_0003.jpeg Informe Final.TXT Presupuesto 2026.ods notas de la reunión.txt
- QuieresExpansiónEjemplo con «Foto Final.JPG»
- Quitar la extensión
${f%.*}Foto Final - Solo la extensión
${f##*.}JPG - Cambiar todos los espacios
${f// /_}Foto_Final.JPG - Minúsculas (Bash 4+)
${f,,}foto final.jpg - Mayúsculas (Bash 4+)
${f^^}FOTO FINAL.JPG - Quitar un prefijo
${f#Foto }Final.JPG
rename, pero hay dos distintas con el mismo nombre: la de Perl (rename 's/\.JPG$/.jpg/' *.JPG), habitual en Debian y Ubuntu, y la de util-linux (rename .JPG .jpg *.JPG), en Fedora y Arch. Los bucles de esta página funcionan igual en todas partes.Todos los scripts de esta página se ejecutaron con Bash 5.3 en Ubuntu 26.04, en un contenedor limpio sin acceso a la red, y pasaron ShellCheck 0.11 sin avisos antes de publicarla; las salidas están copiadas de esa ejecución.