Obniż wszystkie katalogi w katalogu

12

Chcę małe litery w nazwach wszystkich katalogów w katalogu. Za pomocą jakich poleceń mogę to zrobić?

erkangur
źródło

Odpowiedzi:

10

Wszystkie katalogi na jednym poziomie, czy rekurencyjnie?

Zsh

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: zmvzmienia nazwy plików pasujących do wzorca zgodnie z podanym tekstem zastępczym. -o-iprzekazuje -iopcję do każdego mvpolecenia pod maską (patrz poniżej). W tekście zastępczej $1, $2itd, 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 $2na małe litery.

Przenośny

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 -isprawia, że ​​prosi o potwierdzenie w przypadku kolizji. Usuń, -iaby 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 -depthzapewnia, ż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).

Zmiana nazwy Perla

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!' {} +
Gilles „SO- przestań być zły”
źródło
Przynajmniej w OS X to się nie powiedzie, jeśli w katalogach są już małe litery: mv -i a apodaj „mv: zmień nazwę na a / a: Nieprawidłowy argument”.
Janus
@Janus: Racja, pojawia się komunikat o błędzie, który jest brzydki (choć nieszkodliwy w wierszu poleceń). Ale i tak powinienem był użyć zmv, który zajmuje się tą sprawą.
Gilles 'SO - przestań być zły'
Potem odkryłem, -execdirco jest niesamowite: unix.stackexchange.com/questions/5412/ ... Potem odkryłem, że ma trochę PATHszaleństwa i było mi smutno :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
4

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
Shawn J. Goff
źródło
To pokazało się w połowie mojego pisania (w zasadzie tej samej) sugestii:for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
frabjous
Próbowałem to wypracować find -type d, ale nie byłem w stanie tego zrozumieć
Michael Mrozek
1
Mój instynkt byłby taki 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.
Steven D
Tak, bo ... * / byłoby lepiej.
Shawn J. Goff,
1
@Shawn: trjuż 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.
Gilles „SO- przestań być zły”
0

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, findaby 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 -cfind

$ (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!

Janus
źródło
sprawdzanie kolizji jest proste: 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ć, findchyba że rekurencja, a następnie potrzebujesz find -depthi -pathmusisz -name. Zobacz moją odpowiedź dla przykładów roboczych.
Gilles „SO- przestań być zły”
@Giles. Dzięki! Widziałem cię mv -ipo tym, jak to napisałeś. Dobry punkt z cytowaniem ...
Janus
0

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/' '{}' \;

-execdirnajpierw cds do katalogu przed wykonaniem tylko na basenieame.

Niestety nie mogę pozbyć się tej PATHczęści hakowania, find -execdirodmawia 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

Ciro Santilli
źródło