Renomeando arquivos em uma pasta para números seqüenciais


230

Eu quero renomear os arquivos em um diretório para números sequenciais. Com base na data de criação dos arquivos.

Para Exemplo sadf.jpgde 0001.jpg, wrjr3.jpgpara 0002.jpge assim por diante, o número de zeros à esquerda, dependendo da quantidade total de arquivos (sem necessidade de zeros extras se não for necessário).


Eu estive olhando para stackoverflow.com/questions/880467/… , mas não consigo fazer isso funcionar para mim.
Gnutt

1
Linux / Unix não armazena uma data de criação.
Pausado até novo aviso.

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

Respostas:


314

Tente usar um loop let, e printfpara o preenchimento:

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

o uso do -isinalizador impede a substituição automática dos arquivos existentes.


4
Você também pode fazer printf -v new "%04d.jpg" ${a}para colocar o valor na variável E ((a++))trabalha para incrementar a variável. Além disso, isso não ocorre na ordem da data de criação ou minimiza o preenchimento, o que o OP especificou. No entanto, deve-se notar que o Linux / Unix não armazena uma data de criação.
Pausado até novo aviso.

3
Necessário colocar aspas duplas no mv para que isso funcione no meu ambiente bash. mv "$ {i}" "$ {new}"
Gary Thomann

2
Poderia ser apenas Cygwin (embora seu comportamento terminal seja amplamente idêntico aos shells normais do Unix), mas parece ter um problema quando há espaços no nome do arquivo.
Geesh_SO

2
Provavelmente também seria desejável usar mv -- "$i" "$new"para manipular corretamente os nomes de arquivos de origem que começam com hífens; como é, mvtentará analisar nomes de arquivos como coleções de sinalizadores.
Charles Duffy

2
Perdi cerca de 800 arquivos de relance. Eu acho que -ideve ser incluído na resposta e a nota deve ser reescrita de acordo. isso será mais seguro. :(
KrIsHnA 7/17

270

Beleza em uma linha:

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

Você pode mudar .extcom .png, .jpg, etc.


4
legend :), eu usei isso no shell git no windows, funciona muito bem! ^^.
Mr.K

4
Funciona bem. Beleza em uma linha. Adicionei ls -tr os arquivos pela última vez em que foi modificado.
Ranjith Siji

32
adicionar printf assim: ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; donepara ter zero números acolchoadas
Seweryn Niemiec

8
Aviso: -nconvém adicionar ao comando mv para evitar a substituição acidental de arquivos. Descobriu isso da maneira mais difícil!
Ian Danforth

4
Reunindo algumas ótimas idéias dos comentários sobre esta resposta e outras: ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done Resultados: (1) classificados em ordem de modificação, arquivos posteriores com índices posteriores; (2) ignora diretórios - e não recursivo; (3) índices de blocos; (4) mantém a extensão original.
Jorge

63

Gosto da solução de gauteh por sua simplicidade, mas tem uma desvantagem importante. Ao executar em milhares de arquivos, você pode receber a mensagem "lista de argumentos muito longa" ( mais sobre isso ) e, segundo, o script pode ficar muito lento. No meu caso, rodando em aproximadamente 36.000 arquivos, o script mudou aprox. um item por segundo! Não sei ao certo por que isso acontece, mas a regra que recebi dos colegas era " findé seu 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 itens e construir o comando, gawk foi usado. Observe a principal diferença, no entanto. Por padrão, findprocura por arquivos no diretório atual e seus subdiretórios, portanto, certifique-se de limitar a pesquisa apenas no diretório atual, se necessário (use man findpara ver como).


7
Modifiquei para usar o número da linha NRpara um comando mais curto. gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'
Apiwat Chantawibul

12
Grandes vulnerabilidades de segurança aqui. Pense se você tem um arquivo chamado $(rm -rf /).jpg.
Charles Duffy

Obrigado por apontar isso, Charles. Você pode sugerir uma solução segura?
precisa saber é o seguinte

2
quebra caso o nome do arquivo tenha espaços. Use aspas ao redor do nome do arquivo de origem. printf "mv \"% s \ "% 04d.jpg \ n", $ 0, a ++
baskin

1
O forloop não está demorando 1 segundo por arquivo, a rigor. Está demorando muito tempo para buscar os 36.000 nomes de arquivos do sistema de arquivos e os percorre razoavelmente rapidamente. Muitos sistemas de arquivos têm problemas com diretórios grandes, independentemente de quais comandos precisos você executa; mas normalmente, findserá mais rápido que um curinga do shell, pois ele deve buscar e classificar a lista de arquivos correspondentes.
Tripleee 08/01

30

com o comando "renomear"

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

ou

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

32
O meu rename(Linux Mint 13) não tem uma -Nopção.
Lucas H

Eu posso votar apenas pela menção do comando rename, eu nunca ouvi falar dele #
user907860

8
Estou interessado em saber onde se obtém um comando de renomeação com a opção -N. Meu Ubuntu 14.04 não possui.
Stephan Henningsen

1
Adoro o renamecomando, mas nunca soube -N! Obrigado!
21717 Danilo Lecocq

1
Existem pelo menos três ferramentas diferentes conhecidas comorename . O link postado por @Bostrot é mais uma ferramenta de renomeação e parece que @RomanRhrnNesterov usou essa. ¶ Para todos os usuários de renamePeder Stray e Larry Wall (pacote perl-renameno arch linux e pacote renameno debian / ubuntu): Você pode $Nse definir :perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
Socowi

30

usar a solução da Pero no OSX exigiu algumas modificações. Eu usei:

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

nota: as barras invertidas existem para a continuação da linha

editar 20 de julho de 2015: incorporou o feedback de @ klaustopher para citar o \"%s\"argumento do mvcomando para apoiar nomes de arquivos com espaços.


3
Como a solução da Pero, existem vulnerabilidades de segurança aqui. Pense se você tem um arquivo chamado $(rm -rf /).jpg.
Charles Duffy

Obrigado, isso funciona. Mas você deve citar o primeiro argumento para mv. Se você tiver um arquivo chamado, isto é, some thing.jpgseu script falhará. Isto é o que eu usei:find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash
klaustopher

eu provavelmente usaria -maxdepth 1para trabalhar apenas em jpgs no diretório atual, pois é melhor prevenir do que remediar.
Peter Perháč 28/09

Se você mover o caractere de pipe para o final da linha anterior, não precisará de barras invertidas.
Tripleee

você pode usar em ls -1 *.jpgvez de encontrar, caso contrário, não será classificado. Ou adicione um |sort|antes do awk
JPT 08/12/19

28

Um forro de bash one muito simples que mantém as extensões originais, adiciona zeros à esquerda e também funciona no OSX:

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

Versão simplificada do http://ubuntuforums.org/showthread.php?t=1355021


Exatamente o que eu estava procurando. Eu gosto que você possa definir o índice inicial.
Jack Vial

2
Observe que isso não manterá a ordem original dos arquivos.
Roy Shilkrot

@RoyShilkrot O que você quer dizer com » não manterá a ordem original «? Os globos no bash e em outros invólucros posix se expandem em ordem classificada de acordo com a localidade do sistema. Obviamente, isso não está classificado 9.extantes 11.ext, mas outras ferramentas (como ls) também não o fazem.
Socowi 04/06

11

Para trabalhar em todas as situações, coloque \ "para arquivos que possuem espaço no nome

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

3
De fato, não cobre todas as situações. Um nome de arquivo contendo aspas literais pode escapar trivialmente - e como você usa aspas duplas em vez de aspas simples, expansões como $(rm -rf /)essas ainda são respeitadas.
Charles Duffy

11

Se o seu renamenão suportar -N, você pode fazer algo assim:

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

Editar Para começar com um número determinado, você pode usar o código (de aparência um pouco feia) abaixo, basta substituir 123 pelo número desejado:

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

Isso lista os arquivos em ordem no momento da criação (o mais novo primeiro, adicione -rls para classificação inversa) e envia essa lista de arquivos para renomear. Renomear usa código perl no regex para formatar e incrementar o contador.

No entanto, se você estiver lidando com imagens JPEG com informações EXIF, recomendo exiftool

Isso é da documentação do exiftool , em "Renomeando Exemplos"

   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.

Como posso começar com um número específico usando rename?
Jan

6

No OSX , instale o script de renomeação do Homebrew:

brew install rename

Então você pode fazer isso de maneira ridiculamente fácil:

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

Ou, para adicionar um bom prefixo:

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

3
Esse é um ótimo roteiro, e depende apenas do Perl. O brew só funciona em macs, mas você pode acessá- lo no github ( github.com/ap/rename ) e usá-lo no Linux ou Windows.
Tim Danner

3
isso não funciona para mim. Eu conseguiGlobal symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
Anthony Chung

Como usuário de Mac, fico feliz em informar que o aplicativo de renomeação vinculado pelo @TimDanner é super portátil, foi tão fácil quanto baixar o arquivo Zip, soltando o utilitário de renomeação em um diretório que meu caminho do perfil do bash está definido para ver , e funciona imediatamente. Estou surpreso que isso não esteja disponível no MacPorts. Acho tão estranho que possuo uma página de manual do BSD para Renomear (2), mas quando executada renomeia, ele diz que não existe nenhum comando. Vai saber.
adamlogan 02/10/19

2

Siga o comando renomear todos os arquivos para sequenciar e também extensão em minúscula:

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

1

Eu tive um problema semelhante e escrevi um script de shell por esse motivo. Decidi publicá-lo, independentemente de muitas respostas boas já terem sido postadas porque acho que pode ser útil para alguém. Sinta-se livre para melhorá-lo!

numerar

@Gnutt O comportamento que você deseja pode ser alcançado digitando o seguinte:

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

Se a opção -rfor deixada de fora, a fresagem será simulada apenas (deve ser útil para testes).

A ação L descreve o comprimento do número de destino (que será preenchido com zeros à esquerda). Também é possível adicionar um prefixo / sufixo com as opções -p <prefix> -s <suffix>.

Caso alguém queira que os arquivos sejam classificados numericamente antes de serem numerados, basta remover a -o modtimeopção.


1
a=1

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

1

Vamos supor que temos esses arquivos em um diretório, listados em ordem de criação, sendo o primeiro o mais antigo:

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

então ls -1crgera exatamente a lista acima. Você pode então usar rename:

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

quais saídas

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)

O aviso "uso de valor não inicializado […]" é exibido para arquivos sem extensão; você pode ignorá-lo.

Remova -ndo renamecomando para realmente aplicar a renomeação.

Esta resposta é inspirada na resposta de Lucas de abril de 2014 . Ele ignora o requisito de Gnutt de definir o número de zeros à esquerda, dependendo da quantidade total de arquivos.


Essa foi a resposta mais útil aqui para mim, principalmente porque eu queria executar a operação a seco antes da execução, e também porque eu podia ajustar a ordem alterando para ls -1tUa hora da criação. Também precisava ser renameinstalado, o que eu não tinha.
antonyh

1

Novamente, usando a solução da Pero com poucas modificações, porque findestará percorrendo a árvore de diretórios na ordem em que os itens são armazenados nas entradas do diretório. Isso (principalmente) será consistente de execução para execução, na mesma máquina e será essencialmente "ordem de criação de arquivo / diretório" se não houver exclusões.

No entanto, em alguns casos, você precisa obter uma ordem lógica, por exemplo, pelo nome, que é usado neste exemplo.

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
NÃO use isso. Redirecionar para o bash como este é um enorme risco de segurança. E se um dos nomes de arquivo estiver no formato blahblah; rm -r * blahblah.jpg?
xhienne

1

Classificadas por tempo, limitadas a jpg, zeros à esquerda e um nome de base (no caso de você querer um):

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

(tudo em uma linha, sem o \)


No grande esquema das coisas, muitas respostas nesta página são horríveis, então talvez isso não mereça um voto negativo. No lsentanto, hesito em votar em qualquer coisa que use em um script.
Tripleee

Salvei esta resposta do lado negativo, pois, embora talvez frágil, funcionou para um caso de uso específico que eu tinha.
Ville

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

renomear -vn - remove n para o modo fora de teste

{$ i = 1;} - número de início do controle

"% 04d.jpg" - controle a contagem zero 04 e defina a extensão de saída .jpg


A votação desta resposta foi feita, pois ela usa apenas a renomeação nativa. Meu caso de uso foi substituir os dois primeiros dígitos dos arquivos por números começando em 01:rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *
min 12/12/18

1

Para mim, essa combinação de respostas funcionou perfeitamente:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v ajuda a ordenar 1 10 9 corretamente: 1 9 10 ordem, evitando problemas de extensão de nome de arquivo com jpg JPG jpeg
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }'renumera com 4 caracteres e zeros à esquerda. Ao evitar o mv, não tento acidentalmente substituir qualquer coisa que já existe por ter acidentalmente o mesmo número.
  • bash executa

Esteja ciente do que a @xhienne disse: canalizar conteúdo desconhecido para o bash é um risco à segurança. Mas esse não foi o meu caso, pois estava usando minhas fotos digitalizadas.


0

Você também pode usar ls

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

5
Veja mywiki.wooledge.org/ParsingLs e também as descrições de vulnerabilidades de segurança em outras soluções com problemas semelhantes.
Charles Duffy

1
NÃO use isso. Redirecionar para o bash como este é um enorme risco de segurança. E se um dos nomes de arquivo estiver no formato blahblah; rm -r * blahblah.JPG?
Xhienne

0

A maioria das outras soluções substituirá os arquivos existentes já nomeados como um número. Isso é particularmente um problema se você estiver executando o script, adicionando mais arquivos e, em seguida, executando o script novamente.

Este script renomeia os arquivos numéricos existentes primeiro:

#!/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

Esse oneliner lista todos os arquivos no diretório atual, classifica por carimbo de data e hora da criação na ordem inversa (significa que o arquivo mais antigo está no início) e renomeia automaticamente com zeros à direita, conforme exigido pela quantidade de arquivos. A extensão do arquivo será preservada.

Normalmente, só tenho uma pasta há anos para fotos e filmes em celulares. Aplicando esse comando, minhas fotos e filmes estão prontos para uma apresentação de slides na ordem correta na TV ou no arquivamento.

Esteja ciente de que se você tiver colisões de nomes de arquivos, estará perdendo arquivos. Então, primeiro renomeie para algo estranho temp001.jpge, em seguida, execute o seu nome de arquivo 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 lsnão uma vez, mas duas vezes parece que é melhor evitar isso, mas não a estudei em profundidade.
Tripleee

1. Se proponho intencionalmente um oneliner, por que você o altera posteriormente? Muitos usuários como eu preferem copiar e colar um oneliner para que uma tarefa seja concluída. Para outros que preferem copiar linha por linha, existem outras respostas neste tópico. 2. A pergunta original era "o número de zeros à esquerda, dependendo da quantidade total de arquivos", e isso é feito pela primeira vez ls; portanto, é por isso que dois deles são necessários. 3. Esses comandos são one-shots e não pretende ser incluído em scripts, para que haja uma razão pela qual as pessoas preferem one-liners
Flavio Aiello

1
Desculpe, não percebi que você pensava que era importante. Para mim, a capacidade de ler o código supera amplamente a capacidade de copiá-lo / colá-lo como uma única linha. Não encontrei um ambiente em que o Bash tivesse um problema com uma pasta que se estende por várias linhas, mas posso estar ignorando alguma coisa.
Tripleee

0

Aqui está o que funcionou para mim.
Eu usei o comando rename para que, se algum arquivo contiver espaços em seu nome, o comando mv não fique confuso entre os espaços e o arquivo real.

Aqui substituí os espaços '' no nome de um arquivo com '_' para todos os arquivos jpg
#! / bin / bash
renomeie 'y / / _ /' * jpg # substituindo espaços por _
seja x = 0;
para i em * .jpg; faça
    Seja x = (x + 1)
    mv $ i $ x.jpg
feito

Instalar renomear no linux (ubuntu), "sudo apt install rename"
rishang bhavsar 19/03

0

Atualmente, existe uma opção depois de selecionar vários arquivos para renomear (eu já vi no gerenciador de arquivos thunar).

  1. selecione vários arquivos
  2. verificar opções
  3. selecione renomear

Um prompt vem com todos os arquivos nesse diretório específico, basta verificar com a seção categoria


-1

Este script classificará os arquivos por data de criação no Mac OS bash. Eu o uso para renomear vídeos em massa. Apenas mude a extensão e a primeira parte do nome.

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

1
NÃO use isso. Redirecionar para o bash como este é um enorme risco de segurança. E se um dos nomes de arquivo estiver no formato blahblah; rm -r * blahblah.mp4?
xhienne

-1

Aqui está outra solução com o comando "renomear":

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

Para restaurar zeros à esquerda:rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
Camille Goudeseune

Não funciona como esperado, para uma pasta que possui arquivos com nomes como: DSC_3451.JPG, DSC_3452.JPG etc. encontre -name '* .JPG' | classificar -Vr | renomear 's / (\ d +) / $ 1 + 1 / ge' não modifica nada
Tiberiu C.

-2

A resposta de Pero me trouxe aqui :)

Eu queria renomear arquivos em relação ao tempo, pois os visualizadores de imagens não exibiam imagens na ordem do tempo.

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
NÃO use isso. Redirecionar para o bash como este é um enorme risco de segurança. E se um dos nomes de arquivo estiver no formato blahblah; rm -r * blahblah.jpg? Apenas um exemplo extremo.
Xhienne


-3

Para renumerar 6000, arquivos em uma pasta, você pode usar a opção 'Renomear' do programa ACDsee.

Para definir um prefixo, use este formato: ####"*"

Em seguida, defina o número inicial e pressione Renomear para que o programa renomeie todos os 6000 arquivos com números sequenciais.


1
O OP solicita um conjunto de comandos no Unix Bourne Shell. Você está propondo um produto comercial que é executado apenas no ambiente Windows.
Xhienne
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.