Come azzerare i numeri del pad nei nomi dei file in Bash?
Domanda
Qual è il modo migliore, usando Bash, per rinominare i file nel formato:
(foo1, foo2, ..., foo1300, ..., fooN)
Con nomi di file preceduti da zero:
(foo00001, foo00002, ..., foo01300, ..., fooN)
Soluzione
Nel caso N
non è fissato a priori:
for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
Altri suggerimenti
Non è puro bash, ma molto più semplice con il file rename
comando:
rename 's/\d+/sprintf("%05d",$&)/e' foo*
Ho avuto un caso più complesso in cui i nomi dei file avevano un suffisso oltre a un prefisso.Avevo anche bisogno di eseguire una sottrazione del numero dal nome del file.
Ad esempio, volevo foo56.png
diventare foo00000055.png
.
Spero che questo ti aiuti se stai facendo qualcosa di più complesso.
#!/bin/bash
prefix="foo"
postfix=".png"
targetDir="../newframes"
paddingLength=8
for file in ${prefix}[0-9]*${postfix}; do
# strip the prefix off the file name
postfile=${file#$prefix}
# strip the postfix off the file name
number=${postfile%$postfix}
# subtract 1 from the resulting number
i=$((number-1))
# copy to a new name with padded zeros in a new folder
cp ${file} "$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done
Il comando oneline che utilizzo è questo:
ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done
IL MODELLO può essere ad esempio:
- rinominare con incremento contatore:
%04d.${f#*.}
(mantieni l'estensione del file originale) - rinominare con incremento contatore con prefisso:
photo_%04d.${f#*.}
(mantenere l'estensione originale) - rinomina con contatore di incremento e modifica l'estensione in jpg:
%04d.jpg
- rinominare con contatore di incremento con prefisso e nome base del file:
photo_$(basename $f .${f#*.})_%04d.${f#*.}
- ...
Puoi filtrare il file da rinominare, ad esempio ls *.jpg | ...
Hai a disposizione la variabile f
questo è il nome del file e i
quello è il contatore.
Per la tua domanda il comando giusto è:
ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
Pure Bash, nessun processo esterno diverso da "mv":
for file in foo*; do
newnumber='00000'${file#foo} # get number, pack with zeros
newnumber=${newnumber:(-5)} # the last five characters
mv $file foo$newnumber # rename
done
Quanto segue lo farà:
for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done
MODIFICARE: cambiato in usare ((i=1,...)), grazie mweerden!
Ecco una soluzione rapida che presuppone un prefisso di lunghezza fissa (il tuo "foo") e un'imbottitura di lunghezza fissa.Se hai bisogno di maggiore flessibilità, forse questo sarà almeno un utile punto di partenza.
#!/bin/bash
# some test data
files="foo1
foo2
foo100
foo200
foo9999"
for f in $files; do
prefix=`echo "$f" | cut -c 1-3` # chars 1-3 = "foo"
number=`echo "$f" | cut -c 4-` # chars 4-end = the number
printf "%s%04d\n" "$prefix" "$number"
done
La mia soluzione sostituisce i numeri, ovunque in una stringa
for f in * ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf "%04d" $number`
echo $f | sed "s/${number}/${padded}/";
done
Puoi provarlo facilmente, poiché stampa solo i nomi dei file trasformati (non vengono eseguite operazioni sul filesystem).
Spiegazione:
Scorrendo l'elenco dei file
Un ciclo continuo: for f in * ; do ;done
, elenca tutti i file e passa ciascun nome file come $f
variabile al corpo del loop.
Prendendo il numero dalla stringa
Con echo $f | sed
conduciamo la variabile $f
A sed
programma.
Al comando sed 's/[^0-9]*//g'
, parte [^0-9]*
con modificatore ^
dice di abbinare la cifra opposta alla cifra 0-9 (non un numero) e quindi rimuoverla con la sostituzione vuota //
.Perché non semplicemente rimuovere [a-z]
?Poiché il nome file può contenere punti, trattini, ecc.Quindi, eliminiamo tutto ciò che non è un numero e otteniamo un numero.
Successivamente, assegniamo il risultato a number
variabile.Ricorda di non inserire spazi nell'assegnazione, come number = …
, perché ottieni un comportamento diverso.
Assegniamo il risultato dell'esecuzione di un comando alla variabile, avvolgendo il comando con i simboli backtick `.
Imbottitura zero
Comando printf "%04d" $number
cambia il formato di un numero in 4 cifre e aggiunge zeri se il nostro numero contiene meno di 4 cifre.
Sostituzione del numero con un numero riempito con zero
Noi usiamo sed
di nuovo con il comando sostitutivo come s/substring/replacement/
.Per interpretare le nostre variabili, utilizziamo virgolette doppie e sostituiamo le nostre variabili in questo modo ${number}
.
Lo script sopra stampa semplicemente i nomi trasformati, quindi eseguiamo il vero lavoro di ridenominazione:
for f in *.js ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf "%04d" $number`
new_name=`echo $f | sed "s/${number}/${padded}/"`
mv $f $new_name;
done
Spero che questo aiuti qualcuno.
Ho impiegato diverse ore per capirlo.
Per inserire i numeri a sinistra nei nomi dei file:
$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 1.zzz
$ for f in [0-9]*.[a-z]*; do tmp=`echo $f | awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0001.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
Spiegazione
for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
- nota gli apici inversi:
`echo ... $2}\`
(La barra rovesciata, \, immediatamente sopra divide semplicemente quella riga su due righe per facilitare la leggibilità) - in un ciclo trova i file denominati come numeri con estensioni alfabetiche minuscole:
[0-9]*.[a-z]*
- echo quel nome file (
$f
) a cui passarloawk
-F.
:awk
separatore di campo, un punto (.
):se corrispondente, separa i nomi dei file in due campi ($1
= numero;$2
= estensione)- formato con
printf
:stampa il primo campo ($1
, la parte numerica) come 4 cifre (%04d
), quindi stampa il punto, quindi stampa il secondo campo ($2
:l'estensione) come una stringa (%s
).Tutto ciò è assegnato a$tmp
variabile - infine, sposta il file sorgente (
$f
) al nuovo nome file ($tmp
)