Нижнєвикористання всіх каталогів у каталозі


Відповіді:


10

Всі каталоги на одному рівні чи рекурсивно?

Зш

На одному рівні:

autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'

Рекурсивно:

zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'

Пояснення: zmvперейменовує файли, що відповідають шаблону відповідно до заданого тексту заміни. -o-iпередає -iопцію до кожної mvкоманди під кришкою (див. нижче). У тексті заміни, $1, $2і т.д., є послідовною Дужками групи в шаблоні. **означає всі (під) * каталоги, рекурсивно. Фінал (/)- це не дужка група, а глобальний класифікатор, що означає відповідати лише каталогів. ${2:l}перетворюється $2в малі регістри.

Портативний

На одному рівні:

for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done

Фінал /обмежує відповідність каталогів і mv -iзмушує просити підтвердження у випадку зіткнення. Видаліть -iперезапис у разі зіткнення та використовуйте yes n | for …. не вимагати і не виконувати перейменування, яке могло б зіткнутися.

Рекурсивно:

find root/* -depth -type d -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

Використання -depthгарантує, що глибоко вкладені каталоги обробляються перед своїми предками. Обробка імен покладається на те, що існує /; якщо ви хочете, щоб виклик працював у поточному каталозі, використовуйте ./*(адаптуючи сценарій оболонки, щоб впоратися з .чи *залишається як вправа для читача).

Перейменувати Perl

Тут я використовую сценарій перейменування Perl, який Debian і Ubuntu поставляють /usr/bin/prename(як правило, доступні також rename). На одному рівні:

rename 's!/([^/]*/?)$!\L/$1!' root/*/

Рекурсивно, з bash ≥4 або zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/

Рекурсивно, портативно:

find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

Принаймні, на OS X це не вдасться, якщо будь-які каталоги вже мають нижній регістр: mv -i a aдайте "mv: перейменувати a в a / a: Недійсний аргумент".
Янусь

@Janus: Правильно, ви отримуєте повідомлення про помилку, яке є некрасивим (хоча і нешкідливим у командному рядку). Але все одно я повинен був використовувати zmv, який піклується про цю справу.
Жил "ТАК - перестань бути злим"

Потім я виявив, -execdirщо дивовижно: unix.stackexchange.com/questions/5412/… Потім я виявив, що в ньому є якесь PATHбожевілля, і було сумно :-(
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

4

Не існує жодної команди, яка б це зробила, але ви можете зробити щось подібне:

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

Якщо вам потрібно, щоб він був надійним, вам слід врахувати, коли вже є два каталоги, які відрізняються лише у випадку.

Як однолінійний:

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
frabjous

Я намагався розібратися з цим find -type d, але не зміг його отримати
Майкл Мрозек

1
Мій інстинкт мав би робити for fd in */;, таким чином уникаючи необхідності перевірки, якби це був каталог, але я не маю уявлення, чи був цей інстинкт хорошим.
Стівен Д

Так, для ... * / було б краще.
Шон Дж. Гофф

1
@Shawn: trвже чекає діапазон, так tr '[A-Z]' '[a-z]'перекладається [з [і ]в ]мимохідь. Це марно, але нешкідливо; проте без лапок оболонка розширить дужки, якби в поточному каталозі був файл з назвою з великої літери.
Жил "ТАК - перестань бути злим"

0

Я сприйняв це як однолінійне завдання :) Спочатку встановіть тестовий випадок:

$ 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

Я використовую findдля виявлення каталогів з великої літери, а потім зволікаю їх через . Здогадуюсь, це використання трохи злому, але моя голова завжди вибухає, коли я намагаюся уникати речей безпосередньо.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

Будьте попереджені: Це рішення не перевіряє, чи призводить до зниження чисельності!


перевірка зіткнень легко: mv -i. Більша проблема полягає в тому, що ви не використовували належне котирування, тому ваша команда не вдасться, якщо в імені є \[*?десь спеціальні символи (пробіл або ). Немає сенсу користуватися, findякщо не повторюватись, і тоді вам потрібно find -depth, і -pathтреба -name. Дивіться мою відповідь на робочих прикладах.
Жил "ТАК - перестань бути злим"

@Giles. Дякую! Я бачив вашу mv -iпісля написання цього. Хороше запитання з посиланням на ...
Janus

0

find -execdir| перейменувати

Це був би найкращий спосіб зробити це, якби не відносне безумство шляху, оскільки це дозволяє уникнути Perge regex fu діяти лише на базове ім'я:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;

-execdirПерший cds в каталог перед виконанням лише базового імені.

На жаль, я не можу позбутися цієї PATHхакерської частини, find -execdirвідмовляється робити що-небудь, якщо у вас є відносний шлях у PATH...: /ubuntu/621132/why-using-the-execdir-action- це-небезпечно для каталогу, яке-є-в-шляху / 1109378 # 1109378

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.