Będziesz miał problemy, jeśli chcesz zmienić nazwy plików i katalogów w tym samym czasie. Zmiana nazwy tylko pliku jest dość łatwa. Ale chcesz mieć pewność, że nazwy katalogów również zostaną zmienione. Nie można po prostu mv Motörhead/Encöding Motorhead/Encoding
ponieważ Motorhead
nie będzie istnieć w momencie wywołania.
Potrzebujemy więc dogłębnego przejścia wszystkich plików i folderów, a następnie zmień nazwę tylko bieżącego pliku lub folderu. Poniższe działa z GNU find
i Bash 4.2.42 na moim 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
Możesz zmienić wyrażenie regularne, używając, new="${f//[\\\/\:\*\?\"<>|]/}"
jeśli chcesz zastąpić wszystko, czego system Windows nie może obsłużyć.
Zapisz ten skrypt jako rename.sh
, aby można go było wykonać za pomocą chmod +x rename.sh
. Następnie nazwij to tak rename.sh /some/path
.
Pamiętaj, aby rozwiązać wszelkie kolizje nazw plików (komunikaty „ Notice
”).
Jeśli masz absolutną pewność, że dokonuje prawidłowych zamian, usuń echo
skrypt ze skryptu, aby zmienić nazwy rzeczy, zamiast drukować tylko to, co robi.
Dla bezpieczeństwa zalecam najpierw przetestowanie tego na małym podzbiorze plików.
Opcje wyjaśnione
Aby wyjaśnić, co się tutaj dzieje:
-depth
upewni się, że katalogi są rekurencyjnie najpierw na głębokości, abyśmy mogli „zwinąć” wszystko od końca. Zwykle find
trawersuje inaczej (ale nie szerokość).
-print0
zapewnia, że find
dane wyjściowe są rozdzielane zerami, dzięki czemu możemy odczytać je read -d ''
w file
zmiennej. Takie postępowanie pomaga nam radzić sobie z wszelkiego rodzaju dziwnymi nazwami plików, w tym ze spacjami, a nawet znakami nowej linii.
- Otrzymamy katalog pliku z
dirname
. Nie zapomnij, aby zawsze poprawnie cytować zmienne, w przeciwnym razie ścieżka ze spacjami lub znakami globowania złamałaby ten skrypt.
- Otrzymamy rzeczywistą nazwę pliku (lub nazwę katalogu) za pomocą
basename
.
- Następnie usuwamy wszelkie nieprawidłowe znaki z
$f
korzystania z możliwości zamiany ciągów Basha. Nieprawidłowy oznacza wszystko, co nie jest małą lub wielką literą, cyfrą, ukośnikiem ( \/
), kropką ( \.
), podkreśleniem lub łącznikiem minus.
- Jeśli
$f
jest już czysty (wyczyszczona nazwa jest identyczna z bieżącą nazwą), pomiń go.
- Jeśli
$new
już istnieje w katalogu $d
(np. Masz pliki o nazwach resume
i résumé
w tym samym katalogu), wydaj ostrzeżenie. Nie chcesz zmieniać jego nazwy, ponieważ w niektórych systemach mv foo foo
powoduje problem. Inaczej,
- W końcu zmieniamy nazwę oryginalnego pliku (lub katalogu) na jego nową nazwę
Ponieważ będzie to działać tylko w najgłębszej hierarchii, zmiana nazwy Motörhead/Encöding
na Motorhead/Encoding
odbywa się w dwóch krokach:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Zapewnia to, że wszystkie wymiany są wykonywane we właściwej kolejności.
Przykładowe pliki i uruchomienie testowe
Załóżmy, że niektóre pliki w folderze podstawowym o nazwie 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
Oto dane wyjściowe z uruchomienia w trybie debugowania (z echo
przodu przed mv
), tj. Poleceń, które zostaną wywołane, i ostrzeżeń o kolizji:
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é
Zwróć uwagę na brak komunikatów o with-hyphen.txt
, schedule
i test
sama.
mv
już istnieje, co może się zdarzyć (1), jeśli masz pliki, które są już czyste (w wynikumv foo foo
) lub (2), jeśli masz pliki o tej samej nazwie, z wyjątkiem dla znaków specjalnych (np.mv Encöding Encoding
gdzie już maszEncoding
plik opróczEncöding
).