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/Encodingponieważ Motorheadnie 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 findi 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ń echoskrypt 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:
-depthupewni się, że katalogi są rekurencyjnie najpierw na głębokości, abyśmy mogli „zwinąć” wszystko od końca. Zwykle findtrawersuje inaczej (ale nie szerokość).
-print0zapewnia, że finddane wyjściowe są rozdzielane zerami, dzięki czemu możemy odczytać je read -d ''w filezmiennej. 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
$fkorzystania 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
$fjest już czysty (wyczyszczona nazwa jest identyczna z bieżącą nazwą), pomiń go.
- Jeśli
$newjuż istnieje w katalogu $d(np. Masz pliki o nazwach resumei résuméw tym samym katalogu), wydaj ostrzeżenie. Nie chcesz zmieniać jego nazwy, ponieważ w niektórych systemach mv foo foopowoduje 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ödingna Motorhead/Encodingodbywa 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 echoprzodu 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, schedulei testsama.
mvjuż 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 Encodinggdzie już maszEncodingplik opróczEncöding).