Incontrerai alcuni problemi se vuoi rinominare file e directory allo stesso tempo. Rinominare solo un file è abbastanza semplice. Ma vuoi assicurarti che anche le directory vengano rinominate. Non puoi semplicemente mv Motörhead/Encöding Motorhead/Encoding
perché Motorhead
non esisterà al momento della chiamata.
Quindi, abbiamo bisogno di un attraversamento approfondito di tutti i file e cartelle, quindi rinominare solo il file o la cartella corrente. Il seguente funziona con GNU find
e Bash 4.2.42 sul mio OS X.
#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
d="$( dirname "$file" )"
f="$( basename "$file" )"
new="${f//[^a-zA-Z0-9\/\._\-]/}"
if [ "$f" != "$new" ] # if equal, name is already clean, so leave alone
then
if [ -e "$d/$new" ]
then
echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
ls -ld "$d/$new" "$d/$f"
else
echo mv "$file" "$d/$new" # remove "echo" to actually rename things
fi
fi
done
È possibile modificare la regex utilizzando new="${f//[\\\/\:\*\?\"<>|]/}"
se si desidera sostituire tutto ciò che Windows non è in grado di gestire.
Salva questo script come rename.sh
, rendilo eseguibile con chmod +x rename.sh
. Quindi, chiamalo come rename.sh /some/path
.
Assicurati di risolvere eventuali collisioni di nomi di file (" Notice
" annunci).
Se sei assolutamente sicuro di fare i giusti sostituti, rimuovi echo
lo script dallo script per rinominare le cose invece di stampare semplicemente quello che fa.
Per sicurezza, consiglierei prima di provare questo su un piccolo sottoinsieme di file.
Opzioni spiegate
Per spiegare cosa succede qui:
-depth
assicurerà che le directory vengano ripetute in profondità in primo luogo, in modo da poter "arrotolare" tutto dalla fine. Di solito, find
attraversa in modo diverso (ma non prima).
-print0
assicura che l' find
output sia delimitato da null, quindi possiamo leggerlo con read -d ''
nella file
variabile. Ciò ci aiuta a gestire tutti i tipi di nomi di file strani, compresi quelli con spazi e persino le nuove righe.
- Otterremo la directory del file con
dirname
. Non dimenticare di citare sempre correttamente le tue variabili, altrimenti qualsiasi percorso con spazi o personaggi sconvolgenti spezzerebbe questo script.
- Otterremo il nome file attuale (o il nome della directory) con
basename
.
- Quindi, rimuoviamo qualsiasi carattere non valido
$f
dall'uso delle funzionalità di sostituzione delle stringhe di Bash. Invalid indica qualsiasi cosa che non sia una lettera minuscola o maiuscola, una cifra, una barra ( \/
), un punto ( \.
), un carattere di sottolineatura o un trattino meno.
- Se
$f
è già pulito (il nome pulito è identico al nome corrente), saltalo.
- Se
$new
esiste già nella directory $d
(ad esempio, hai i file con nome resume
e résumé
nella stessa directory), emetti un avviso. Non vuoi rinominarlo, perché, su alcuni sistemi, mv foo foo
causa un problema. Altrimenti,
- Alla fine rinominiamo il file (o la directory) originale con il suo nuovo nome
Poiché questo agirà solo sulla gerarchia più profonda, la ridenominazione Motörhead/Encöding
in Motorhead/Encoding
viene eseguita in due passaggi:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Ciò garantisce che tutte le sostituzioni vengano eseguite nell'ordine corretto.
File di esempio ed esecuzione del test
Supponiamo che alcuni file in una cartella di base chiamata test
:
test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule
Ecco l'output di una corsa in modalità debug (con il echo
davanti a mv
), ovvero i comandi che verrebbero chiamati e gli avvisi di collisione:
mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r-- … … test/work/resume
-rw-r—r-- … … test/work/résumé
Si noti l'assenza di messaggi per with-hyphen.txt
, schedule
e test
per sé.
mv
esiste già la destinazione del , che può accadere (1) se hai file già puliti (risultantimv foo foo
), o (2) se hai file con lo stesso nome tranne per i caratteri speciali (ad es.mv Encöding Encoding
, dove hai già unEncoding
file in aggiunta aEncöding
).