Renombrar archivos en una carpeta a números secuenciales


230

Quiero cambiar el nombre de los archivos en un directorio a números secuenciales. Basado en la fecha de creación de los archivos.

Por ejemplo sadf.jpga 0001.jpg, wrjr3.jpga 0002.jpg, y así sucesivamente, el número de ceros a la izquierda, dependiendo de la cantidad total de archivos (sin necesidad de ceros adicionales si no es necesario).


He estado buscando en stackoverflow.com/questions/880467/… , pero no puedo hacer que eso funcione para mí.
Gnutt

1
Linux / Unix no almacena una fecha de creación.
Pausado hasta nuevo aviso.

1
ls -1tr | cambie el nombre de -v 's /.*/ our $ i; if (! $ i) {$ i = 1;} sprintf ("% 04d.jpg", $ i ++) / e'
maXp

Respuestas:


314

Intente usar un bucle let, y printfpara el relleno:

a=1
for i in *.jpg; do
  new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
  mv -i -- "$i" "$new"
  let a=a+1
done

El uso de la -ibandera evita sobrescribir automáticamente los archivos existentes.


44
También puede hacer printf -v new "%04d.jpg" ${a}para poner el valor en la variable. Y ((a++))trabaja para incrementar la variable. Además, esto no lo hace en el orden de la fecha de creación ni minimiza el relleno que son las cosas que especificó el OP. Sin embargo, debe tenerse en cuenta que Linux / Unix no almacena una fecha de creación.
Pausado hasta nuevo aviso.

3
Necesitaba comillas dobles para envolver el mv para que esto funcione en mi entorno bash. mv "$ {i}" "$ {new}"
Gary Thomann

2
Podría ser Cygwin (aunque su comportamiento terminal es en gran medida idéntico a los shells normales de Unix), pero parece tener un problema cuando hay espacios en el nombre del archivo.
Geesh_SO

2
Probablemente también sería deseable usarlo mv -- "$i" "$new"para manejar correctamente los nombres de los archivos de origen que comienzan con guiones; tal como está, mvintentará analizar dichos nombres de archivos como colecciones de banderas.
Charles Duffy

2
He perdido unos 800 archivos de un vistazo. Creo que -idebería incluirse en la respuesta y la nota debería reescribirse en consecuencia. Eso será más seguro. :(
KrIsHnA

270

Belleza en una linea:

ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done 

Puede cambiar .extcon .png, .jpg, etc.


44
leyenda :), lo usé en git shell en windows, ¡funciona muy bien! ^^.
Mr.K

44
Funciona genial. Belleza en una sola línea. Agregué ls -tr obtener los archivos por última vez modificada.
Ranjith Siji

32
agregue printf así: ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; donetener cero números rellenados
Seweryn Niemiec

8
Advertencia: es posible que desee agregar -nal comando mv para evitar sobrescribir accidentalmente los archivos. Descubierto esto de la manera difícil!
Ian Danforth

44
Reuniendo algunas ideas geniales de los comentarios sobre esta respuesta y otras: ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done Resultados: (1) ordenados por orden de modificación, archivos posteriores con índices posteriores; (2) ignora los directorios, y no es recursivo; (3) índices de pads; (4) mantiene la extensión original.
Jorge

63

Me gusta la solución de Gauteh por su simplicidad, pero tiene un inconveniente importante. Cuando se ejecuta en miles de archivos, puede obtener el mensaje "lista de argumentos demasiado larga" ( más sobre esto ), y en segundo lugar, el script puede ser realmente lento. En mi caso, ejecutándolo en aproximadamente 36,000 archivos, el script se movió aprox. ¡un artículo por segundo! No estoy muy seguro de por qué sucede esto, pero la regla que obtuve de mis colegas fue " findes tu amigo" .

find -name '*.jpg' | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

Para contar elementos y construir comandos, se utilizó gawk . Tenga en cuenta la principal diferencia, sin embargo. Por defecto findbusca archivos en el directorio actual y sus subdirectorios, así que asegúrese de limitar la búsqueda en el directorio actual solo, si es necesario (use man findpara ver cómo).


77
Modifiqué para usar el número de fila NRpara un comando más corto. gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'
Apiwat Chantawibul

12
Enormes vulnerabilidades de seguridad aquí. Piensa si tienes un archivo llamado $(rm -rf /).jpg.
Charles Duffy

Gracias por señalar eso Charles. ¿Puedes sugerir una solución segura?
beibei2

2
se desglosa en caso de que el nombre de archivo tenga espacios. Use comillas alrededor del nombre del archivo fuente. printf "mv \"% s \ "% 04d.jpg \ n", $ 0, a ++
baskin

1
El forciclo no está tomando 1 segundo por archivo, estrictamente hablando. Está tomando mucho tiempo obtener los 36,000 nombres de archivo del sistema de archivos, luego los recorre razonablemente rápido. Muchos sistemas de archivos tienen problemas con directorios grandes, independientemente de los comandos precisos que ejecute; pero, por lo general, findserá más rápido que un comodín de shell porque tiene que buscar y ordenar la lista de archivos coincidentes.
tripleee

30

con el comando "renombrar"

rename -N 0001 -X 's/.*/$N/' *.jpg

o

rename -N 0001 's/.*/$N.jpg/' *.jpg

32
Mi rename(Linux Mint 13) no tiene una -Nopción.
Luke H

Puedo votar solo por la mención del comando de cambio de nombre, nunca he oído hablar de él
Dmitry Korolyov

8
Estoy interesado en saber dónde se obtiene un comando de cambio de nombre con la opción -N. Mi Ubuntu 14.04 no lo tiene.
Stephan Henningsen

1
Me encanta el renamecomando, ¡pero nunca lo supe -N! ¡Gracias!
Dan Lecocq

1
Hay al menos tres herramientas diferentes conocidas comorename . El enlace publicado por @Bostrot es otra herramienta de cambio de nombre y parece que @RomanRhrnNesterov usó esa. ¶ Para todos los usuarios de renamePeder Stray y Larry Wall (paquete perl-renameen arch linux y paquete renameen debian / ubuntu): Puedes definirte a $Nti mismo:perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
Socowi

30

El uso de la solución de Pero en OSX requirió alguna modificación. Solía:

find . -name '*.jpg' \
| awk 'BEGIN{ a=0 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' \
| bash

nota: las barras invertidas están ahí para continuar la línea

editar 20 de julio de 2015: incorporó los comentarios de @ klaustopher para citar el \"%s\"argumento del mvcomando con el fin de admitir nombres de archivos con espacios.


3
Al igual que la solución de Pero, aquí hay vulnerabilidades de seguridad. Piensa si tienes un archivo llamado $(rm -rf /).jpg.
Charles Duffy

Gracias, esto funciona. Pero deberías citar el primer argumento para mv. Si tiene un archivo llamado, es decir, some thing.jpgsu secuencia de comandos falla. Esto es lo que usé:find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash
klaustopher

Probablemente usaría -maxdepth 1para trabajar solo en jpgs en el directorio actual, ya que es mejor prevenir que curar.
Peter Perháč

Si mueve el carácter de la tubería al final de la línea anterior, no necesita barras invertidas.
tripleee

puede usar en ls -1 *.jpglugar de buscar, de lo contrario no se ordenará. O agregue un |sort|antes de awk
JPT

28

Un bash one liner muy simple que mantiene las extensiones originales, agrega ceros a la izquierda y también funciona en OSX:

num=0; for i in *; do mv "$i" "$(printf '%04d' $num).${i#*.}"; ((num++)); done

Versión simplificada de http://ubuntuforums.org/showthread.php?t=1355021


Exactamente lo que estaba buscando. Me gusta que pueda establecer el índice de inicio.
Jack Vial

2
Tenga en cuenta que esto no mantendrá el orden original de los archivos.
Roy Shilkrot

@RoyShilkrot ¿Qué quiere decir con " no mantendrá el orden original "? Los globos en bash y otros proyectiles posix se expanden en orden de acuerdo con la ubicación del sistema. Por supuesto, esto no se ordena 9.extantes 11.ext, pero otras herramientas (como ls) tampoco lo harán.
Socowi

11

Para trabajar en todas las situaciones, coloque un \ "para los archivos que tienen espacio en el nombre

find . -name '*.jpg' | gawk 'BEGIN{ a=1 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' | bash

3
De hecho, no cubre todas las situaciones. Un nombre de archivo que contiene comillas literales podría escapar trivialmente, y dado que está usando comillas dobles en lugar de comillas simples, las expansiones como $(rm -rf /)todavía se respetan.
Charles Duffy

11

Si su renameno es compatible -N, puede hacer algo como esto:

ls -1 -c | xargs rename -n 's/.*/our $i; sprintf("%04d.jpg", $i++)/e'

Editar Para comenzar con un número dado, puede usar el código (algo feo) a continuación, simplemente reemplace 123 con el número que desee:

ls -1 -c | xargs rename -n 's/.*/our $i; if(!$i) { $i=123; } sprintf("%04d.jpg", $i++)/e'

Esto enumera los archivos en orden por hora de creación (los más nuevos primero, agregue -r a ls para ordenarlos de forma inversa), luego envía esta lista de archivos para cambiar el nombre. Renombrar usa código perl en la expresión regular para formatear e incrementar el contador.

Sin embargo, si está tratando con imágenes JPEG con información EXIF, le recomendaría exiftool

Esto es de la documentación de exiftool , en "Ejemplos de cambio de nombre"

   exiftool '-FileName<CreateDate' -d %Y%m%d_%H%M%S%%-c.%%e dir

   Rename all images in "dir" according to the "CreateDate" date and time, adding a copy number with leading '-' if the file already exists ("%-c"), and
   preserving the original file extension (%e).  Note the extra '%' necessary to escape the filename codes (%c and %e) in the date format string.

¿Cómo puedo comenzar con un número específico usando rename?
Jan

6

En OSX , instale el script de cambio de nombre de Homebrew:

brew install rename

Entonces puedes hacerlo realmente ridículamente fácil:

rename -e 's/.*/$N.jpg/' *.jpg

O para agregar un buen prefijo:

rename -e 's/.*/photo-$N.jpg/' *.jpg

3
Es un gran guión, y solo depende de Perl. brew solo funciona en Mac, pero puede tomarlo de github ( github.com/ap/rename ) y usarlo en Linux o Windows.
Tim Danner

3
Esto no funciona para mí. TengoGlobal symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
Anthony Chung

Como usuario de Mac, me complace informar que la aplicación de cambio de nombre vinculada por @TimDanner es súper portátil, fue tan fácil como descargar el archivo Zip, soltando la utilidad de cambio de nombre en un directorio que mi ruta de perfil bash está configurada para ver , y funciona desde el primer momento. Me sorprende que esto no esté disponible en MacPorts. Me resulta tan extraño que tengo una página de manual de BSD para Rename (2) pero cuando se ejecuta rename dice que no existe ningún comando. Imagínate.
adamlogan

2

Siga el comando cambiar el nombre de todos los archivos a la secuencia y también la extensión en minúsculas:

rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *

1

Tuve un problema similar y escribí un script de shell por esa razón. He decidido publicarlo independientemente de que ya se hayan publicado muchas buenas respuestas porque creo que puede ser útil para alguien. ¡Siéntete libre de mejorarlo!

numerar

@Gnutt El comportamiento que desea puede lograrse escribiendo lo siguiente:

./numerate.sh -d <path to directory> -o modtime -L 4 -b <startnumber> -r

Si la opción -r se deja fuera, el escariado solo se simulará (debería ser útil para las pruebas).

La opción L describe la longitud del número objetivo (que se rellenará con ceros a la izquierda). También es posible agregar un prefijo / sufijo con las opciones -p <prefix> -s <suffix> .

En caso de que alguien quiera que los archivos se ordenen numéricamente antes de que se numeren, simplemente elimine la -o modtimeopción.


1
a=1

for i in *.jpg; do
 mv -- "$i" "$a.jpg"
 a=`expr $a + 1`
done

1

Supongamos que tenemos estos archivos en un directorio, en orden de creación, siendo el primero el más antiguo:

a.jpg
b.JPG
c.jpeg
d.tar.gz
e

luego ls -1crgenera exactamente la lista anterior. Entonces puedes usar rename:

ls -1cr | xargs rename -n 's/^[^\.]*(\..*)?$/our $i; sprintf("%03d$1", $i++)/e'

que salidas

rename(a.jpg, 000.jpg)
rename(b.JPG, 001.JPG)
rename(c.jpeg, 002.jpeg)
rename(d.tar.gz, 003.tar.gz)
Use of uninitialized value $1 in concatenation (.) or string at (eval 4) line 1.
rename(e, 004)

La advertencia "uso de valor no inicializado [...]" se muestra para archivos sin extensión; Puedes ignorarlo.

Eliminar -nde larename comando para aplicar realmente el cambio de nombre.

Esta respuesta está inspirada en la respuesta de Luke de abril de 2014 . Ignora el requisito de Gnutt de establecer el número de ceros a la izquierda dependiendo de la cantidad total de archivos.


Esta fue la respuesta más útil aquí para mí, principalmente porque quería ejecutar la operación en seco antes de que se ejecutara, y también porque podía ajustar el orden cambiando a ls -1tUtiempo de creación. También necesitaba renameinstalarse, lo cual no tenía.
antonyh

1

Nuevamente usando la solución de Pero con poca modificación, porque find que atravesará el árbol del directorio en el orden en que los elementos se almacenan dentro de las entradas del directorio. Esto (en su mayoría) será consistente de una ejecución a otra, en la misma máquina y esencialmente será un "orden de creación de archivo / directorio" si no ha habido eliminaciones.

Sin embargo, en algunos casos necesita obtener un orden lógico, por ejemplo, por nombre, que se utiliza en este ejemplo.

find -name '*.jpg' | sort -n | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command 

3
NO utilices esto. Redirigir a una fiesta como esta es un riesgo de seguridad masivo. ¿Qué pasa si uno de los nombres de archivo tiene la forma blahblah; rm -r * blahblah.jpg?
xhienne

1

Ordenado por tiempo, limitado a jpg, ceros a la izquierda y un nombre base (en caso de que probablemente desee uno):

ls -t *.jpg | cat -n |                                           \
while read n f; do mv "$f" "$(printf thumb_%04d.jpg $n)"; done

(todo en una línea, sin el \)


En el gran esquema de las cosas, muchas respuestas en esta página son horribles, por lo que tal vez esto no merece particularmente un voto negativo. Sin lsembargo, dudo en votar cualquier cosa que use en un script.
tripleee

Guardo esta respuesta desde el lado negativo, ya que aunque quizás sea frágil, funcionó para un caso de uso específico que tenía.
Ville

1
ls -1tr | rename -vn 's/.*/our $i;if(!$i){$i=1;} sprintf("%04d.jpg", $i++)/e'

rename -vn - elimina n para el modo de prueba

{$ i = 1;} - número de inicio de control

"% 04d.jpg" : controla el recuento cero 04 y establece la extensión de salida .jpg


Votar esta respuesta ya que solo usa el cambio de nombre nativo. Mi caso de uso fue reemplazar los dos primeros dígitos de los archivos por números a partir del 01:rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *
minterior

1

Para mí, esta combinación de respuestas funcionó perfectamente:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v ayuda a ordenar 1 10 9 en el orden correcto: 1 9 10, evitando problemas de extensión de nombre de archivo con jpg JPG jpeg
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }'renumeraciones con 4 caracteres y ceros a la izquierda. Al evitar mv, no intento sobrescribir accidentalmente algo que ya existe al tener accidentalmente el mismo número.
  • bash ejecuta

Tenga en cuenta lo que @xhienne dijo, canalizar contenido desconocido para golpear es un riesgo de seguridad. Pero este no fue el caso para mí, ya que estaba usando mis fotos escaneadas.


0

También puedes usar ls

ls *.JPG| awk 'BEGIN{ a=0 }{ printf "mv %s gopro_%04d.jpg\n", $0, a++ }' | bash

55
Consulte mywiki.wooledge.org/ParsingLs , y también las descripciones de vulnerabilidades de seguridad en las otras soluciones igualmente rotas.
Charles Duffy

1
NO utilices esto. Redirigir a una fiesta como esta es un riesgo de seguridad masivo. ¿Qué pasa si uno de los nombres de archivo tiene la forma blahblah; rm -r * blahblah.JPG?
xhienne

0

La mayoría de las otras soluciones sobrescribirán los archivos existentes ya nombrados como un número. Esto es particularmente un problema si ejecuta el script, agrega más archivos y luego ejecuta el script nuevamente.

Este script cambia el nombre de los archivos numéricos existentes primero:

#!/usr/bin/perl

use strict;
use warnings;

use File::Temp qw/tempfile/;

my $dir = $ARGV[0]
    or die "Please specify directory as first argument";

opendir(my $dh, $dir) or die "can't opendir $dir: $!";

# First rename any files that are already numeric
while (my @files = grep { /^[0-9]+(\..*)?$/ } readdir($dh))
{
    for my $old (@files) {
        my $ext = $old =~ /(\.[^.]+)$/ ? $1 : '';
        my ($fh, $new) = tempfile(DIR => $dir, SUFFIX => $ext);
        close $fh;
        rename "$dir/$old", $new;
    }
}

rewinddir $dh;
my $i;
while (my $file = readdir($dh))
{
    next if $file =~ /\A\.\.?\z/;
    my $ext = $file =~ /(\.[^.]+)$/ ? $1 : '';
    rename "$dir/$file", sprintf("%s/%04d%s", $dir, ++$i, $ext); 
}

0

Este oneliner enumera todos los archivos en el directorio actual, ordena por marca de tiempo de creación en orden inverso (significa que el archivo más antiguo está al principio) y cambia el nombre automáticamente con ceros finales según lo requiera la cantidad de archivos. La extensión del archivo se conservará.

Por lo general, solo tengo una carpeta desde hace años para fotos y películas de teléfonos móviles. Aplicando este comando, mis imágenes y películas están listas para una presentación de diapositivas en el orden correcto en la televisión o el archivo también.

Tenga en cuenta que si tiene colisiones de nombres de archivos, está perdiendo archivos. Así que primero cambie el nombre a algo extraño temp001.jpgy luego ejecútelo en su nombre de archivo final.

DIGITS=$(ls | wc -l | xargs | wc -c | xargs); ls -tcr | cat -n | while read n f; do mv "$f" "$(printf "%0${DIGITS}d" $n).${f##*.}"; done

1
Correr lsno una, sino dos veces, parece que esto debería evitarse, pero no lo he estudiado en profundidad.
tripleee

1. Si propongo intencionalmente una línea, ¿por qué la cambia después? Muchos usuarios como yo prefieren copiar y pegar un oneliner para completar una tarea. Para otros que prefieren copiar línea por línea, hay otras respuestas en este hilo. 2. La pregunta original era "el número de ceros a la izquierda dependiendo de la cantidad total de archivos" y esto se hace por el primero ls, por eso se requieren dos de ellos. 3. Tales comandos son de una sola vez y no están destinados a ser incluidos en los scripts, por lo que hay una razón por la cual las personas prefieren frases sencillas
Flavio Aiello

1
Lo siento, no me di cuenta de que pensabas que eso era importante. Para mí, poder leer el código supera enormemente la capacidad de copiarlo / pegarlo como una sola línea. No he encontrado un entorno en el que Bash tenga un problema con una pasta que abarque varias líneas, pero puedo pasar por alto algo.
tripleee

0

Esto es lo que funcionó para mí.
He utilizado el comando renombrar para que si algún archivo contiene espacios en su nombre, el comando mv no se confunda entre espacios y el archivo real.

Aquí reemplacé espacios, '' en un nombre de archivo con '_' para todos los archivos jpg
#! / bin / bash
renombrar 'y / / _ /' * jpg # reemplazando espacios con _
let x = 0;
para i en * .jpg; hacer
    let x = (x + 1)
    mv $ i $ x.jpg
hecho

Instalar rename en linux (ubuntu), "sudo apt install rename"
rishang bhavsar

0

Hoy en día hay una opción después de seleccionar varios archivos para cambiar el nombre (lo he visto en el administrador de archivos thunar).

  1. seleccione múltiples archivos
  2. verificar opciones
  3. seleccione renombrar

Un aviso viene con todos los archivos en ese directorio en particular, solo verifique con la sección de categoría


-1

Este script ordenará los archivos por fecha de creación en Mac OS bash. Lo uso para renombrar videos en masa. Simplemente cambie la extensión y la primera parte del nombre.

ls -trU *.mp4| awk 'BEGIN{ a=0 }{ printf "mv %s lecture_%03d.mp4\n", $0, a++ }' | bash

1
NO utilices esto. Redirigir a una fiesta como esta es un riesgo de seguridad masivo. ¿Qué pasa si uno de los nombres de archivo tiene la forma blahblah; rm -r * blahblah.mp4?
xhienne

-1

Aquí otra solución con el comando "renombrar":

find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'

Para restaurar los ceros a la izquierda:rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
Camille Goudeseune

No funciona como se esperaba, para una carpeta que tiene archivos con nombres como este: DSC_3451.JPG, DSC_3452.JPG etc. find -name '* .JPG' | ordenar -Vr | renombrar 's / (\ d +) / $ 1 + 1 / ge' no modifica nada
Tiberiu C.

-2

La respuesta de Pero me trajo aquí :)

Quería cambiar el nombre de los archivos en relación con el tiempo, ya que los visores de imágenes no mostraban las imágenes en orden de tiempo.

ls -tr *.jpg | # list jpegs relative to time
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

2
NO utilices esto. Redirigir a una fiesta como esta es un riesgo de seguridad masivo. ¿Qué pasa si uno de los nombres de archivo tiene la forma blahblah; rm -r * blahblah.jpg? Solo un ejemplo extremo.
xhienne


-3

Para renumerar 6000, los archivos en una carpeta puede usar la opción 'Cambiar nombre' del programa ACDsee.

Para definir un prefijo, use este formato: ####"*"

Luego configure el número de inicio y presione Cambiar nombre y el programa cambiará el nombre de los 6000 archivos con números secuenciales.


1
El OP solicita un conjunto de comandos en Unix Bourne Shell. Está proponiendo un producto comercial que solo se ejecuta en un entorno Windows.
xhienne
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.