Rinominare i file in una cartella in numeri sequenziali


230

Voglio rinominare i file in una directory in numeri sequenziali. In base alla data di creazione dei file.

Ad esempio sadf.jpga 0001.jpg, wrjr3.jpga 0002.jpge così via, il numero di zeri iniziali a seconda della quantità totale di file (non è necessario alcuno zero aggiuntivo se non necessario).


Ho esaminato stackoverflow.com/questions/880467/… , ma non riesco a farlo funzionare per me.
Gnutt,

1
Linux / Unix non memorizzano una data di creazione.
In pausa fino a nuovo avviso.

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

Risposte:


314

Prova a usare un loop let, e printfper il riempimento:

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

l'uso del -iflag impedisce la sovrascrittura automatica dei file esistenti.


4
Puoi anche fare printf -v new "%04d.jpg" ${a}per inserire il valore nella variabile. E ((a++))lavora per incrementare la variabile. Inoltre, ciò non lo fa nell'ordine della data di creazione o minimizza il riempimento, che è ciò che l'OP ha specificato. Tuttavia, va notato che Linux / Unix non memorizzano una data di creazione.
In pausa fino a nuovo avviso.

3
Avevo bisogno di raddoppiare le virgolette per avvolgere la MV per farlo funzionare nel mio ambiente bash. mv "$ {i}" "$ {new}"
Gary Thomann l'

2
Potrebbe essere solo Cygwin (anche se il suo comportamento terminale è in gran parte identico alle normali shell Unix) ma sembra avere un problema quando ci sono spazi nel nome del file.
Geesh_SO,

2
Probabilmente sarebbe anche desiderabile utilizzare mv -- "$i" "$new"per gestire correttamente i nomi dei file di origine che iniziano con trattini; così com'è, mvproverà ad analizzare tali nomi di file come raccolte di bandiere.
Charles Duffy,

2
Ho perso circa 800 file a colpo d'occhio. Penso che -idovrebbe essere incluso nella risposta e la nota dovrebbe essere riscritta di conseguenza. sarà più sicuro. :(
KrIsHnA

270

Bellezza in una riga:

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

È possibile modificare .extcon .png, .jpgecc


4
legenda :), l'ho usato su git shell su windows, funziona benissimo! ^^.
Mr.K

4
Funziona alla grande. Bellezza in una riga. Ho aggiunto ls -tr per ottenere i file dall'ultima modifica.
Ranjith Siji,

32
aggiungi printf in questo modo: ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; doneper avere zero numeri imbottiti
Seweryn Niemiec,

8
Avvertenza: potresti voler aggiungere -nil comando mv per evitare la sovrascrittura accidentale dei file. L'ho scoperto nel modo più duro!
Ian Danforth,

4
Mettere insieme alcune grandi idee dai commenti su questa risposta e altri: ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done Risultati: (1) ordinati in ordine di modifica, file successivi con indici successivi; (2) ignora le directory - e non ricorsive; (3) indici dei pad; (4) mantiene l'estensione originale.
Jorge,

63

Mi piace la soluzione di gauteh per la sua semplicità, ma ha un importante svantaggio. Quando si esegue su migliaia di file, è possibile ottenere il messaggio "Elenco argomenti troppo lungo" ( altro su questo ) e, in secondo luogo, lo script può diventare molto lento. Nel mio caso, eseguendolo su circa 36.000 file, lo script si è spostato di ca. un oggetto al secondo! Non sono davvero sicuro del perché questo accada, ma la regola che ho ricevuto dai colleghi era " findè tuo amico" .

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

Per contare gli oggetti e creare il comando, è stato usato gawk . Nota la differenza principale, però. Per impostazione predefinita findcerca i file nella directory corrente e nelle sue sottodirectory, quindi assicurati di limitare la ricerca solo nella directory corrente, se necessario (usa man findper vedere come).


7
Ho modificato per utilizzare il numero di riga NRper un comando più breve. gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'
Apiwat Chantawibul,

12
Enormi vulnerabilità di sicurezza qui. Pensa se hai un file chiamato $(rm -rf /).jpg.
Charles Duffy,

Grazie per averlo segnalato Charles. Puoi suggerire una soluzione sicura?
Beibei2,

2
si rompe nel caso in cui il nome file contenga spazi. Usa le virgolette attorno al nome del file sorgente. printf "mv \"% s \ "% 04d.jpg \ n", $ 0, a ++
baskin

1
Il forciclo non richiede 1 secondo per file, in senso stretto. Ci vuole molto tempo per recuperare i 36.000 nomi di file dal file system, quindi li circola ragionevolmente rapidamente. Molti file system hanno problemi con directory di grandi dimensioni, indipendentemente dai comandi precisi che esegui; ma in genere, findsarà più veloce di un carattere jolly shell perché deve recuperare e ordinare l'elenco dei file corrispondenti.
triplo

30

con il comando "rinomina"

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

o

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

32
Il mio rename(Linux Mint 13) non ha -Nun'opzione.
Luca H

Posso votare solo per la menzione del comando rename, non ne ho mai sentito parlare
user907860

8
Sono interessato a sapere dove si ottiene un comando di ridenominazione con l'opzione -N. Il mio Ubuntu 14.04 non ce l'ha.
Stephan Henningsen,

1
Adoro il renamecomando, ma non l'ho mai saputo -N! Grazie!
Dan Lecocq,

1
Esistono almeno tre diversi strumenti noti comerename . Il link pubblicato da @Bostrot è ancora un altro strumento di ridenominazione e sembra che @RomanRhrnNesterov l'abbia usato. ¶ A tutti gli utenti di renamePeder Stray e Larry Wall (pacchetto perl-renamesu Arch Linux e pacchetto renamesu Debian / Ubuntu): Puoi $Nperl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
definirti

30

l'utilizzo della soluzione di Pero su OSX ha richiesto alcune modifiche. Ero solito:

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

nota: le barre rovesciate sono lì per la continuazione della linea

modifica 20 luglio 2015: incorporato il feedback di @ klaustopher per citare l' \"%s\"argomento del mvcomando al fine di supportare i nomi di file con spazi.


3
Come la soluzione di Pero, qui ci sono vulnerabilità di sicurezza. Pensa se hai un file chiamato $(rm -rf /).jpg.
Charles Duffy,

Grazie, funziona. Ma dovresti citare il primo argomento a mv. Se hai un file chiamato ie lo some thing.jpgscript non riesce. Questo è quello che ho usato:find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash
klaustopher,

probabilmente -maxdepth 1userei lavorare solo su jpg nella directory corrente, poiché è meglio prevenire che curare.
Peter Perháč,

Se sposti il ​​carattere pipe alla fine della riga precedente, non hai bisogno di barre rovesciate.
triplo

puoi usare ls -1 *.jpginvece di trovare, altrimenti non verrà ordinato. O aggiungi un |sort|prima awk
JPT

28

Un semplice bash one liner che mantiene le estensioni originali, aggiunge zeri iniziali e funziona anche in OSX:

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

Versione semplificata di http://ubuntuforums.org/showthread.php?t=1355021


Esattamente quello che stavo cercando. Mi piace che puoi impostare l'indice iniziale.
Jack Vial

2
Si noti che ciò non manterrà l' ordine originale dei file.
Roy Shilkrot,

@RoyShilkrot Cosa intendi con » non manterrà l'ordine originale «? I globi in bash e altre shell posix si espandono in modo ordinato in base alle impostazioni locali del sistema. Naturalmente, questo non ordina 9.extprima 11.ext, ma anche altri strumenti (come ls) non lo faranno.
Socowi,

11

Per funzionare in tutte le situazioni, metti un \ "per i file che hanno spazio nel nome

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

3
In realtà non copre tutte le situazioni. Un nome di file contenente virgolette letterali potrebbe banalmente scappare - e poiché stai usando virgolette doppie anziché virgolette singole, le espansioni come $(rm -rf /)sono ancora onorate.
Charles Duffy,

11

Se il tuo renamenon supporta -N, puoi fare qualcosa del genere:

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

Modifica Per iniziare con un determinato numero, è possibile utilizzare il codice (un po 'brutto) di seguito, basta sostituire 123 con il numero desiderato:

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

Questo elenca i file in ordine di tempo di creazione (prima il più recente, aggiungi -ra ls per invertire l'ordinamento), quindi invia questo elenco di file da rinominare. Rinomina utilizza il codice perl nella regex per formattare e incrementare il contatore.

Tuttavia, se hai a che fare con immagini JPEG con informazioni EXIF, lo consiglierei exiftool

Questo è dalla documentazione di exiftool , sotto "Rinomina esempi"

   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.

Come posso iniziare da un numero specifico usando rename?
Jan

6

Su OSX , installa lo script di rinomina da Homebrew:

brew install rename

Quindi puoi farlo davvero ridicolmente facilmente:

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

O per aggiungere un bel prefisso:

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

3
È una sceneggiatura fantastica, e dipende solo da Perl. brew funziona solo su Mac, ma puoi prenderlo da github ( github.com/ap/rename ) e usarlo su Linux o Windows.
Tim Danner,

3
questo non funziona per me. Ho avutoGlobal symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
Anthony Chung il

Come utente Mac, sono felice di segnalare che l'applicazione di ridenominazione collegata da @TimDanner è super portatile, è stato facile come scaricare l'archivio Zip, trascinando l'utilità di ridenominazione in una directory che il mio percorso del profilo bash è impostato per vedere e funziona immediatamente. Sono sorpreso che questo non sia disponibile su MacPorts. Lo trovo così strano che ho una manpage BSD per Rename (2) ma quando esegui rename direi che non esiste alcun comando. Vai a capire.
adamlogan,

2

Segui il comando rinomina tutti i file in sequenza e anche l'estensione in minuscolo:

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

1

Ho avuto un problema simile e ho scritto uno script di shell per questo motivo. Ho deciso di pubblicarlo indipendentemente dal fatto che molte buone risposte fossero già state pubblicate perché penso che possa essere utile per qualcuno. Sentiti libero di migliorarlo!

che sa contare

@Gnutt Il comportamento desiderato può essere ottenuto digitando quanto segue:

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

Se l'opzione -rviene lasciata fuori, l'alesatura sarà solo simulata (dovrebbe essere utile per i test).

L'otione L descrive la lunghezza del numero target (che sarà riempito con zeri iniziali) è anche possibile aggiungere un prefisso / suffisso con le opzioni -p <prefix> -s <suffix>.

Nel caso in cui qualcuno desideri che i file vengano ordinati numericamente prima di essere numerati, basta rimuovere l' -o modtimeopzione.


1
a=1

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

1

Supponiamo di avere questi file in una directory, elencati in ordine di creazione, il primo è il più vecchio:

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

quindi ls -1crrestituisce esattamente l'elenco sopra. È quindi possibile utilizzare rename:

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

quali uscite

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)

L'avvertimento "uso di valore non inizializzato [...]" viene visualizzato per i file senza estensione; puoi ignorarlo.

Rimuovi -ndal renamecomando per applicare effettivamente la ridenominazione.

Questa risposta è ispirata alla risposta di Luke dell'aprile 2014 . Ignora il requisito di Gnutt di impostare il numero di zeri iniziali in base alla quantità totale di file.


Questa è stata la risposta più utile qui per me, principalmente perché volevo eseguire l'operazione a secco prima che fosse eseguita, e anche perché potevo ottimizzare l'ordine cambiando in ls -1tUper il momento della creazione. Aveva anche bisogno di essere renameinstallato, cosa che non avevo.
antonyh,

1

Di nuovo usando la soluzione di Pero con poche modifiche, perché findattraverserà l'albero delle directory nell'ordine in cui gli elementi vengono memorizzati nelle voci della directory. Questo sarà (principalmente) coerente da una corsa all'altra, sulla stessa macchina e sarà essenzialmente "ordine di creazione di file / directory" se non ci sono state cancellazioni.

Tuttavia, in alcuni casi è necessario ottenere un ordine logico, ad esempio, per nome, utilizzato in questo esempio.

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
NON usare questo. Il reindirizzamento a bash in questo modo è un enorme rischio per la sicurezza. Cosa succede se uno dei nomi di file è nel modulo blahblah; rm -r * blahblah.jpg?
Xhienne

1

Ordinati per tempo, limitati a jpg, zeri iniziali e un nome di base (nel caso tu ne voglia uno):

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

(tutto su una riga, senza il \)


Nel grande schema delle cose, molte risposte in questa pagina sono orribili, quindi forse questo non merita particolarmente un voto negativo. lsTuttavia esito a votare tutto ciò che utilizza in una sceneggiatura.
triplo

Salvo questa risposta dal lato negativo poiché, sebbene forse fragile, ha funzionato per un caso d'uso specifico che avevo.
Ville

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

rinomina -vn - rimuove n per la modalità off test

{$ i = 1;} - controlla il numero iniziale

"% 04d.jpg" - controlla il conteggio zero 04 e imposta l'estensione di output .jpg


L'upgrade di questa risposta in quanto utilizza solo la ridenominazione nativa. Il mio caso d'uso è stato quello di sostituire le prime due cifre dei file con numeri che iniziano a 01:rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *
min

1

Per me questa combinazione di risposte ha funzionato perfettamente:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v aiuta a ordinare 1 10 9 nell'ordine corretto: 1 9 10, evitando problemi di estensione del nome file con jpg jpg JPG
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }'renumbers con 4 caratteri e zeri iniziali. Evitando mv non provo per caso a sovrascrivere qualsiasi cosa sia già presente avendo accidentalmente lo stesso numero.
  • bash esegue

Fai attenzione a ciò che ha detto @xhienne, inviare un contenuto sconosciuto a bash è un rischio per la sicurezza. Ma questo non è stato il caso per me mentre stavo usando le mie foto scansionate.


0

Puoi anche usare ls

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

5
Vedi mywiki.wooledge.org/ParsingLs e anche le descrizioni delle vulnerabilità di sicurezza nell'altra, soluzioni analogamente rotte.
Charles Duffy,

1
NON usare questo. Il reindirizzamento a bash in questo modo è un enorme rischio per la sicurezza. Cosa succede se uno dei nomi di file è nel modulo blahblah; rm -r * blahblah.JPG?
Xhienne,

0

La maggior parte delle altre soluzioni sovrascriverà i file esistenti già nominati come numeri. Questo è particolarmente un problema se si esegue lo script, si aggiungono più file e si esegue nuovamente lo script.

Questo script rinomina innanzitutto i file numerici esistenti:

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

Questo oneliner elenca tutti i file nella directory corrente, ordina per timestamp di creazione in ordine inverso (significa che il file più vecchio è all'inizio) e rinomina automaticamente con zeri finali come richiesto dalla quantità di file. L'estensione del file verrà preservata.

Di solito ho solo una cartella da anni per le foto e i film sul cellulare. Applicando questo comando, le mie foto e i miei filmati sono pronti per una presentazione nell'ordine corretto sulla tv o anche per l'archiviazione.

Tenere presente che se si verificano collisioni di nomi di file, si stanno perdendo file. Quindi prima rinominate qualcosa di strano temp001.jpge poi eseguite il nome del file finale.

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
Correre lsnon una volta ma due volte sembra che questo dovrebbe essere evitato, ma non l'ho studiato a fondo.
triplo

1. Se propongo intenzionalmente un oneliner, perché lo cambi in seguito? Molti utenti come me preferiscono copiare e incollare un oneliner per completare un'attività. Per altri che preferiscono copiare riga per riga, ci sono altre risposte in questo thread. 2. La domanda originale era "il numero di zeri iniziali a seconda della quantità totale di file" e questo viene fatto dal primo ls, quindi è necessario il motivo per cui ne sono richiesti due. 3. Tali comandi sono one-shot e non sono pensati per essere inclusi negli script, quindi c'è un motivo per cui le persone preferiscono le battute singole
Flavio Aiello

1
Scusa, non avevo capito che pensavi fosse importante. Per me, essere in grado di leggere il codice supera notevolmente la possibilità di copiarlo / incollarlo come una singola riga. Non ho trovato un ambiente in cui Bash avrebbe un problema con un incolla che si estende su più righe, ma potrei trascurare qualcosa.
triplo

0

Ecco cosa ha funzionato per me.
Ho usato il comando rename in modo che se un file contiene spazi nel nome di esso, il comando mv non viene confuso tra spazi e file reale.

Qui ho sostituito gli spazi, "" in un nome di file con "_" per tutti i file jpg
#! / Bin / bash
rinomina 'y / / _ /' * jpg # sostituendo gli spazi con _
lascia x = 0;
per i in * .jpg; fare
    lascia x = (x + 1)
    mv $ i $ x.jpg
fatto

Installa rinominare su Linux (Ubuntu), "sudo apt install rinominare"
rishang bhavsar

0

Oggi c'è un'opzione dopo aver selezionato più file per la ridenominazione (ho visto nel file manager thunar).

  1. seleziona più file
  2. controlla le opzioni
  3. seleziona rinomina

Un prompt arriva con tutti i file in quella particolare directory, basta controllare con la sezione categoria


-1

Questo script ordina i file per data di creazione su Mac OS Bash. Lo uso per rinominare in massa i video. Basta cambiare l'estensione e la prima parte del nome.

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

1
NON usare questo. Il reindirizzamento a bash in questo modo è un enorme rischio per la sicurezza. Cosa succede se uno dei nomi di file è nel modulo blahblah; rm -r * blahblah.mp4?
Xhienne,

-1

Ecco un'altra soluzione con il comando "rinomina":

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

Per ripristinare gli zeri rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
iniziali

Non funziona come previsto, per una cartella che ha file con nomi come questo: DSC_3451.JPG, DSC_3452.JPG ecc. Find -name '* .JPG' | ordina -Vr | rename 's / (\ d +) / $ 1 + 1 / ge' non modifica nulla
Tiberiu C.

-2

La risposta di Pero mi ha portato qui :)

Volevo rinominare i file relativamente al tempo poiché i visualizzatori di immagini non visualizzavano le immagini in ordine di 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
NON usare questo. Il reindirizzamento a bash in questo modo è un enorme rischio per la sicurezza. Cosa succede se uno dei nomi di file è nel modulo blahblah; rm -r * blahblah.jpg? Solo un esempio estremo.
Xhienne,


-3

Per rinumerare 6000 file in una cartella, è possibile utilizzare l'opzione "Rinomina" del programma ACDsee.

Per definire un prefisso usa questo formato: ####"*"

Quindi impostare il numero iniziale e premere Rinomina e il programma rinominerà tutti i 6000 file con numeri sequenziali.


1
L'OP richiede una serie di comandi in Unix Bourne Shell. Stai proponendo un prodotto commerciale che funziona solo in ambiente Windows.
Xhienne,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.