Rename to Start Case or Initial Caps in Bash
Мне нужен oneliner, чтобы переименовать все файлы в каталоге из
SomeThing.TXT НЕ ФАЙЛ.ogg чувствительный lalala.doc
в
Something.txt Не файл.ogg Чувствительный Lalala.doc
Другими словами: первые буквы слов являются заглавными, а все остальное - строчными. Это называется начальный регистр или начальные заглавные буквы. Это очень близко к "Заголовку дела". Расширение файла должно быть в нижнем регистре.
Большинство существующих вопросов, кажется, имеют дело только с именами файлов UPPERCASE.MKV или lowercase.mkv, но ни один из них не охватывает Capitalized Case.mkv ( пример).
Все распространенные инструменты, такие как трубы, sed
, perl
, grep
и больше можно использовать.
4 ответа
Я придумал быстрое решение в виде одной строки:
for f in *; do mv -i "$f" "`echo $f | sed -e 's/\(.*\)/\L\1/' -e 's/\( .\)/\U\1/g' -e 's/\(^.\)/\U\1/g'`"; done
Или в удобочитаемой (но немного менее удобной для копирования форме вставки):
for f in *; do
mv -i "$f" "`echo $f |
sed -e 's/\(.*\)/\L\1/' -e 's/\( .\)/\U\1/g' -e 's/\(^.\)/\U\1/g'`";
done
Эта команда использует sed
в mv
каждый файл в файл с тем же именем, но в котором все символы сначала переводятся в нижний регистр, затем каждая комбинация пробела, за которым следует любой символ, переводится в верхний регистр, затем первый символ - в верхний регистр.
Это будет спрашивать перед перезаписью.
Удалить -i
если вы хотите, чтобы он автоматически перезаписывал.
Если у вас есть доступ к perl rename (по умолчанию устанавливается как rename
в системах на основе Debian, доступно как perl-rename
на многих других), вы можете запустить:
rename 's/.*/lc($&)/e; s/(^| )./uc($&)/ge' *
Объяснение:
rename
Программа запустит выражение perl для каждого из своих имен входных файлов. Здесь первая операция замещения (s///
) заменит все (.*
) с собой ($&
это то, что было найдено), но в нижнем корпусе (lc($&)
). Второй, будет соответствовать каждому символу после пробела или в начале имени файла ((^| )
) и замените его версией в верхнем регистре (uc($&)
).
Беги с -n
флаг для проверки без внесения каких-либо изменений:
$ rename -n 's/.*/lc($&)/e; s/ ./uc($&)/ge' *
rename NOT A FILE.ogg not A File.ogg
rename sensitive lalala.doc sensitive Lalala.doc
rename SomeThing.TXT something.txt
Вы также можете использовать цикл оболочки и Perl:
for f in *; do
mv "$f" "$(perl -lpe 's/.*/lc($&)/e; s/(^| )./uc($&)/ge' <<<"$f")"
done
Это та же команда, что и в rename
выше, только мы передаем его каждому файлу в каталоге и используем подстановку команд для переименования.
Вы можете легко изменить это, чтобы избежать перезаписи существующих файлов:
for f in *; do
target="$(perl -lpe 's/.*/lc($&)/e; s/(^| )./uc($&)/ge' <<<"$f")";
[ -e "$target" ] &&
echo "File \"$target\" exists, skipping \"$f\"" ||
mv "$f" "$target";
done
Это работает на Bash 3.2.57
для Mac OSX
Предварительный просмотр (ничего не меняет):
IFS=$'\n';FOLDER=new;for F in $(ls -1);do EXT="${F##*.}";NAME="${F%.*}";NEW=$(echo "$NAME"| perl -pe 's/[ _-]([A-z0-9])([^ _-]+)/ \U\1\L\2/g');echo "cp '$F' '$FOLDER/$NEW.$EXT'";done
Если предварительный просмотр выглядит хорошо, вы можете использовать это, чтобы переименовать и зайти в подпапку:
IFS=$'\n';FOLDER=new;[ -d $FOLDER ] || mkdir $FOLDER;for F in $(ls -1);do EXT="${F##*.}";NAME="${F%.*}";NEW=$(echo "$NAME"| perl -pe 's/[ _-]([A-z0-9])([^ _-]+)/ \U\1\L\2/g');cp -v "$F" "$FOLDER/$NEW.$EXT";done
Заметки:
- Не изменит расширение файла.
- Должны правильно обрабатывать числа.
- Если у вас есть другие символы, которые вы хотите преобразовать в пробелы, просто добавьте их в класс символов:
[ _-]
- Предотвращает конфликты имен, превращая копию каждого файла в подпапку. Это дает вам возможность отмены. Другой способ справиться с этим - переименовать все файлы, добавив такой префикс, как
_My New File Name.jpg
, а затем переименуйте все эти версии в версии без_
,