Как переименовать все папки и файлы в нижнем регистре на Linux?
Мне нужно рекурсивно переименовать полное дерево папок, чтобы нигде не появлялась заглавная буква (это исходный код C++, но это не имеет значения). Бонусные баллы за игнорирование файлов/папок управления CVS и SVN. Предпочтительным способом будет сценарий оболочки, так как оболочка должна быть доступна в любой Linux-системе.
были некоторые допустимые аргументы о деталях переименования файла.
Я думаю, что файлы с одинаковыми именами в нижнем регистре должны быть перезаписаны, это проблема пользователя. При извлечении на случай игнорирования файловой системы будет перезаписать первый с последним, тоже.
Я бы рассмотрел символы A-Z и преобразовал их в a-z, все остальное просто вызывает проблемы (по крайней мере, с исходным кодом).
скрипт будет необходим для запуска сборки в системе Linux, поэтому я думаю, что изменения в CVS или SVN файлы управления должны быть опущены. В конце концов, это всего лишь скретч-чек. Возможно "экспорт" более уместен.
24 ответа:
краткий вариант с использованием .
find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/\/\L/' {} \;
это позволяет избежать проблем с переименованием каталогов перед файлами и попыткой переместить файлы в несуществующие каталоги (например,
"A/A"
на"a/a"
).или, более подробная версия без использования
"rename"
.for SRC in `find my_root_dir -depth` do DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'` if [ "${SRC}" != "${DST}" ] then [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed" fi done
П. С.
последний позволяет больше гибкости с командой перемещения (например,
"svn mv"
).
еще меньше мне нравится
rename 'y/A-Z/a-z/' *
в нечувствительных к регистру файловых системах, таких как OS X HFS+, вы захотите добавить флаг-f
rename -f 'y/A-Z/a-z/' *
просто попробуйте следовать, если вам не нужно заботиться об эффективности.
zip -r foo.zip foo/* unzip -LL foo.zip
большинство ответов выше опасны, потому что они не имеют дело с именами, содержащими нечетные символы. Ваша самая безопасная ставка для такого рода вещей-использовать опцию find-print0, которая завершит имена файлов с ascii NUL вместо \n. здесь я представляю этот скрипт, который только изменяет файлы, а не имена каталогов, чтобы не путать find.
find . -type f -print0 | xargs -0n 1 bash -c \ 's=$(dirname "")/$(basename ""); d=$(dirname "")/$(basename ""|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'
Я тестировал его, и он работает с именами файлов, содержащими пробелы, все виды кавычек и т. д. Это важно, потому что если вы запустите, как root, один из тех других скриптов в дереве, который включает файл, созданный:
touch \;\ echo\ hacker::0:0:hacker:$\'7\'root:$\'7\'bin$\'7\'bash
... Ну знаешь что ...
это работает если у вас уже есть или создать переименовать команда (например, через brew install в Mac):
rename --lower-case --force somedir/*
С помощью Larry Wall's filename fixer
$op = shift or die $help; chomp(@ARGV = <STDIN>) unless @ARGV; for (@ARGV) { $was = $_; eval $op; die $@ if $@; rename($was,$_) unless $was eq $_; }
это просто
find | fix 'tr/A-Z/a-z/'
(где исправить, конечно, скрипт выше)
исходный вопрос, заданный для игнорирования каталогов SVN и CVS, который можно сделать, добавив-prune в команду find. Например, чтобы игнорировать CVS:
find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print
[edit] я попробовал это, и внедрение перевода нижнего регистра внутри находки не сработало по причинам, которые я на самом деле не понимаю. Итак, измените это следующим образом:
$> cat > tolower #!/bin/bash mv `echo | tr '[:upper:]' '[:lower:]'` ^D $> chmod u+x tolower $> find . -name CVS -prune -o -exec tolower '{}' \;
Иэн
вот мое неоптимальное решение, используя сценарий оболочки bash:
#!/bin/bash # first, rename all folders for f in `find . -depth ! -name CVS -type d`; do g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'` if [ "xxx$f" != "xxx$g" ]; then echo "Renaming folder $f" mv -f "$f" "$g" fi done # now, rename all files for f in `find . ! -type d`; do g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'` if [ "xxx$f" != "xxx$g" ]; then echo "Renaming file $f" mv -f "$f" "$g" fi done
Edit: я сделал некоторые изменения, основанные на предложениях до сих пор. Теперь папки все переименованы правильно, mv не задает вопросы, когда разрешения не совпадают, и папки CVS не переименованы (файлы управления CVS внутри этой папки все еще переименованы, к сожалению).
Edit: поскольку "find-depth" и "find | sort-r" оба возвращают список папок в удобном порядке для переименования, я предпочел использование "- глубина " для поиска папок.
Это небольшой скрипт, который делает то, что вы просили:
root_directory="${1?-please specify parent directory}" do_it () { awk '{ lc= tolower(); if (lc != ) print "mv \"" "\" \"" lc "\"" }' | sh } # first the folders find "$root_directory" -depth -type d | do_it find "$root_directory" ! -type d | do_it
обратите внимание на действие-глубина в первой находке.
это работает на CentOS / Redhat или других дистрибутивах без
rename
Perl-скрипт:for i in $( ls | grep [A-Z] ); do mv -i "$i" "`echo $i | tr 'A-Z' 'a-z'`"; done
Источник: https://linuxconfig.org/rename-all-files-from-uppercase-to-lowercase-characters
(в некоторых дистрибутивах по умолчанию
rename
команда исходит из util-linux, и это другой, несовместимый инструмент)
ранее опубликованное будет работать отлично из коробки или с несколькими корректировками для простых случаев, но есть некоторые ситуации, которые вы можете принять во внимание перед запуском пакетного переименования:
что должно произойти, если у вас есть два или более имен на одном уровне в иерархии путей, которые отличаются только по регистру, например
ABCdef
,abcDEF
иaBcDeF
? Должен ли сценарий переименования прерваться или просто предупредить и продолжить?как сделать вы определяете нижний регистр для имен, отличных от US-ASCII? Если такие имена могут присутствовать, следует ли сначала проверить и исключить проход?
Если вы выполняете операцию переименования на рабочих копиях CVS или SVN, вы можете повредить рабочую копию, если измените обращение на имена файлов или каталогов. Если сценарий также найти и настроить внутренние административные файлы, такие как .svn / записи или CVS / записи?
С MacOS,
установить
rename
пакет,brew install rename
использовать
find . -iname "*.py" -type f | xargs -I% rename -c -f "%"
эта команда находит все файлы с
не портативный, только Zsh, но довольно лаконичный.
во-первых, убедитесь, что
zmv
загружается.autoload -U zmv
кроме того, убедитесь, что
extendedglob
на:setopt extendedglob
затем использовать:
zmv '(**/)(*)~CVS~**/CVS' '${(L)2}'
рекурсивно строчные файлы и каталоги, где имя не CVS.
в OSX mv-f показывает ошибку "тот же файл", поэтому я переименовываю дважды.
for i in `find . -name "*" -type f |grep -e "[A-Z]"`; do j=`echo $i | tr '[A-Z]' '[a-z]' | sed s/\-1$//`; mv $i $i-1; mv $i-1 $j; done
Я бы потянулся к python в этой ситуации, чтобы избежать оптимистически предполагать пути без пробелов или косых черт. Я также обнаружил, что
python2
имеет тенденцию устанавливаться в большем количестве мест, чемrename
.#!/usr/bin/env python2 import sys, os def rename_dir(directory): print('DEBUG: rename('+directory+')') # rename current directory if needed os.rename(directory, directory.lower()) directory = directory.lower() # rename children for fn in os.listdir(directory): path = os.path.join(directory, fn) os.rename(path, path.lower()) path = path.lower() # rename children within, if this child is a directory if os.path.isdir(path): rename_dir(path) # run program, using the first argument passed to this python script as the name of the folder rename_dir(sys.argv[1])
for f in `find -depth`; do mv ${f} ${f,,} ; done
find -depth
печатает каждый файл и каталог, причем содержимое каталога печатается перед самим каталогом.${f,,}
в нижнем регистре имя файла.
( find YOURDIR -type d | sort -r; find yourdir -type f ) | grep -v /CVS | grep -v /SVN | while read f; do mv -v $f `echo $f | tr '[A-Z]' '[a-z]'`; done
сначала переименуйте каталоги снизу вверх sort-r (где-глубина недоступна), затем файлы. Тогда grep-v / CVS вместо найти ...-чернослив потому что это проще. Для больших каталогов для f В... может переполнить некоторые буферы оболочки. Используйте найти ... | пока читаю чтобы избежать этого.
и да, это будет clobber файлы, которые отличаются только в случае...
Slugify переименовать (регулярное выражение)
не совсем то, что ОП попросил, но то, что я надеялся найти на этой странице:
версия "slugify" для переименования файлов, чтобы они были похожи на URL-адреса
(т. е. только включать буквенно-цифровые, точки и тире):rename "s/[^a-zA-Z0-9\.]+/-/g" filename
мне нужно было сделать это на установке cygwin в Windows 7 и обнаружил, что я получил синтаксические ошибки с предложениями сверху, которые я пробовал (хотя я, возможно, пропустил рабочий вариант), однако это решение прямо из ubutu форумов работал из банки :-)
ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done
(nb я ранее заменял пробелы подчеркиванием с помощью
for f in *\ *; do mv "$f" "${f// /_}"; done
если вы используете Arch Linux, вы можете установить
rename
пакета изAUR
обеспечивает
никто не предлагает набирать?
typeset -l new # always lowercase find $topPoint | # not using xargs to make this more readable while read old do mv "$old" "$new" # quotes for those annoying embedded spaces done
на эмуляциях windows, таких как git bash, это может не сработать, потому что windows не чувствительна к регистру под капотом. Для них добавьте шаг, который mv-это файл с другим именем, например " $old.tmp", затем до $new.
Длительным, Но "Работает Без Сюрпризов И Без Установки"
этот скрипт ручками имена файлов с пробелами, кавычками, другой необычно символы и Unicode, работает на нечувствительных к регистру файловых системах и большинстве Unix-y сред у которых установлены bash и awk (т. е. почти все). Он также сообщает о коллизиях, если таковые имеются (оставляя имя файла в верхнем регистре) и, конечно, переименовывает оба файла и каталоги и работает рекурсивно. Наконец, это очень легко адаптируется: вы можете настроить команду find для таргетинга файлов/dirs, которые вы хотите, и вы можете настроить awk для выполнения других манипуляций с именами. Обратите внимание, что под "ручками Unicode" я имею в виду, что он действительно преобразует их случай (не игнорируйте их, как ответы, которые используют
tr
).# adapt the following command _IF_ you want to deal with specific files/dirs find . -depth -mindepth 1 -exec bash -c ' for file do # adapt the awk command if you wish to rename to something other than lowercase newname=$(dirname "$file")/$(basename "$file" | awk "{print tolower($0)}") if [ "$file" != "$newname" ] ; then # the extra step with the temp filename is for case-insensitive filesystems if [ ! -e "$newname" ] && [ ! -e "$newname.lcrnm.tmp" ] ; then mv -T "$file" "$newname.lcrnm.tmp" && mv -T "$newname.lcrnm.tmp" "$newname" else echo "ERROR: Name already exists: $newname" fi fi done ' sh {} +
ссылки
мой скрипт основан на этих превосходных ответы:
https://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names