Odpowiedzi:
Wszystkie katalogi na jednym poziomie, czy rekurencyjnie?
Na jednym poziomie:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Rekurencyjnie:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Objaśnienia: zmv
zmienia nazwy plików pasujących do wzorca zgodnie z podanym tekstem zastępczym. -o-i
przekazuje -i
opcję do każdego mv
polecenia pod maską (patrz poniżej). W tekście zastępczej $1
, $2
itd, są kolejne grupy w nawiasach we wzorcu. **
oznacza rekursywnie wszystkie (pod) * katalogi. Finał (/)
nie jest grupą w nawiasach, ale globalnym kwalifikatorem, który oznacza dopasowanie tylko do katalogów. ${2:l}
konwertuje $2
na małe litery.
Na jednym poziomie:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
Finał /
ogranicza dopasowanie do katalogów i mv -i
sprawia, że prosi o potwierdzenie w przypadku kolizji. Usuń, -i
aby zastąpić w przypadku kolizji, i użyj yes n | for …
. nie wyświetlać monitu i nie wykonywać żadnej zmiany nazwy, która by kolidowała.
Rekurencyjnie:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
Zastosowanie -depth
zapewnia, że głęboko zagnieżdżone katalogi są przetwarzane przed ich przodkami. Przetwarzanie nazw polega na tym, że istnieje /
; jeśli chcesz wywołać operację w bieżącym katalogu, użyj ./*
(dostosuj skrypt powłoki, aby poradził sobie z .
lub *
pozostanie jako ćwiczenie dla czytelnika).
Tutaj używam skryptu zmiany nazwy Perla, który dostarczają Debian i Ubuntu /usr/bin/prename
(zwykle również dostępny rename
). Na jednym poziomie:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Rekurencyjnie, z bash ≥4 lub zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Rekurencyjnie, przenośnie:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdir
co jest niesamowite: unix.stackexchange.com/questions/5412/ ... Potem odkryłem, że ma trochę PATH
szaleństwa i było mi smutno :-(
Nie ma na to ani jednego polecenia, ale możesz zrobić coś takiego:
for fd in */; do
#get lower case version
fd_lower=$(printf %s "$fd" | tr A-Z a-z)
#if it wasn't already lowercase, move it.
[ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done
Jeśli potrzebujesz, aby był solidny, powinieneś wziąć pod uwagę, gdy istnieją już dwa katalogi, które różnią się tylko w przypadku.
Jako jedna linijka:
for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d
, ale nie byłem w stanie tego zrozumieć
for fd in */;
, unikając w ten sposób potrzeby sprawdzania, czy był to katalog, ale nie mam pojęcia, czy ten instynkt był dobry.
tr
już oczekuje zasięgu, więc tr '[A-Z]' '[a-z]'
przekłada się [
na [
i ]
na przemian ]
. Jest to bezużyteczne, ale nieszkodliwe; jednak bez cudzysłowów powłoka rozszerzyłaby nawiasy, gdyby w bieżącym katalogu znajdował się plik o nazwie składającej się z wielkich liter.
Wziąłem to za jedno-liniowe wyzwanie :) Najpierw ustal przypadek testowy:
$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar aBar.txt aeVe.txt afoo.txt eVe foo
Używam, find
aby wykryć katalogi dużymi literami, a następnie przeliterować je za pomocą . Zgaduję, że używanie jest trochę hackingowe, ale moja głowa zawsze eksploduje, gdy próbuję bezpośrednio uciec przed rzeczami .sh -c 'mv {}
echo {} | tr [:upper:] [:lower:]
'sh -c
find
$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt aeVe.txt afoo.txt bar eve foo
Uwaga: to rozwiązanie nie sprawdza, czy zmniejszanie prowadzi do kolizji!
mv -i
. Większy problem polega na tym, że nie użyłeś poprawnego cytowania, więc twoje polecenie zakończy się niepowodzeniem, jeśli \[*?
w nazwie występują znaki specjalne (białe znaki lub ). Nie ma sensu używać, find
chyba że rekurencja, a następnie potrzebujesz find -depth
i -path
musisz -name
. Zobacz moją odpowiedź dla przykładów roboczych.
mv -i
po tym, jak to napisałeś. Dobry punkt z cytowaniem ...
find -execdir
| Przemianować
Byłby to najlepszy sposób, aby to zrobić, gdyby nie względne szaleństwo ścieżki, ponieważ pozwala uniknąć działania wyrażeń regularnych Perl tylko na basenieame:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdir
najpierw cd
s do katalogu przed wykonaniem tylko na basenieame.
Niestety nie mogę pozbyć się tej PATH
części hakowania, find -execdir
odmawia zrobienia czegokolwiek, jeśli masz względną ścieżkę w PATH
...: /ubuntu/621132/why-using-the-execdir-action- is-niepewne-dla-katalogu-który-jest-na-ścieżce / 1109378 # 1109378
mv -i a a
podaj „mv: zmień nazwę na a / a: Nieprawidłowy argument”.