Сам вопрос тоже не точный, потому что ФП говорит о:
- имена файлов вроде
ABC 123456(без расширения), но в примере кода используется *.txtрасширение
- добавить тире между двумя блоками (например, где находится пробел), как
ABC - 123456, но в следующем, counting to 4и count 3, например, не совсем ясно, что скрипт должен делать, например, если найти ABCD 12илиAB 345
- Кроме того, хочу сохранить конечный пробел, что странно - но хорошо;)
Задача делится на 3 отдельные части:
- выбор правильных файлов для переименования
- подготовка нового имени файла, замена / добавление символов в старое
- «физическое» переименование
Объявление "Выбор правильных файлов". Выбор файлов может быть сделан некоторыми внешними утилитами, например, findкомандой. Основными преимуществами findявляются:
- он может искать файлы рекурсивно в подкаталогах тоже
- можно точнее выбрать нужные файлы, например исключить каталоги, выбрать файлы по времени или размеру и так далее. (проверьте из терминала
man find.)
Объявление "подготовить новое имя". Это может быть сделано внешними программами, такими как sedили awkлюбая другая программа, которая может манипулировать текстом в сценариях оболочки, или это может быть сделано (в некоторых простых случаях, таких как это) с помощью bashсамого себя - и возможно сохранить выполнение одной дорогой команды. (для тысяч файлов это имеет значение).
Последующий:
${file/ /-}
заменяет (заменяет) один пробел ( / /часть) тире ( /-). Так что можно написать
mv "$file" "${file/ /-}"
и сохранить sedисполнение.
Таким образом, одним из альтернативных решений может быть , например, следующее:
#!/bin/bash
while IFS= read -r -d $'\0' filename
do
newfilename="${filename/ /-}"
[[ "$filename" != "$newfilename" ]] && echo mv -i "$filename" "$newfilename"
done < <(find . -maxdepth 1 -type f -iname "* *.jpg" -print0)
Гробница предназначена для СУХОГО ЗАПУСКА - она только покажет, что будет сделано, для реального выполнения удалите echo.
Распад:
выбрав нужные файлы для переименования: find . -maxdepth 1 -type f -iname "* *.jpg" -print0найдет все
- что только в текущем каталоге (
-maxdepth 1)
- и они простые файлы (
-type f)
- и их имя совпадает (что угодно) (пробел) (что угодно) .jpg без учета регистра - например, имя должно содержать пробел
- поставьте имена файлов как завершенные нулем , так что их имя также может безопасно содержать символ новой строки. (
-print0)
цикл while IFS= read -r -d $'\0' filename; do ... done < <( )
- читает вывод из вышеуказанной
findкоманды
- где имена файлов заканчиваются нулем (
-d $'\0')
- игнорировать любые экранированные символы (
-r) / расширенная тема - здесь объяснять не нужно /
- что
IFS= предотвращает Обрезка начальные и конечные пробелы из имени файла (также, немного сложная тема)
готовит новое имя файла newfilename="${filename/ /-}"
- делается
bashвнутренне (без выполнения внешней команды).
- если хотите сохранить задний интервал после использования тире
${filename/ /- }
фактическое переименование выполняется mvкомандой (см. man mvиз терминала), где
-iчто будет спрашивать пользователя , если здесь уже имеется файл с новым именем (не отменяют его)
и mvвыполняется только тогда, когда newfilenameотличается отfilename [[ "$filename" != "$newfilename" ]]
Вышеупомянутое решение в основном подвержено ошибкам, но оно все еще не очень эффективно, потому что для сотен тысяч файлов mvкоманда будет выполняться в сотни тысяч раз . Решением может быть: использование некоторой утилиты, которая может прочитать имена файлов и выполнить переименование, не выполняя mvкоманду N-раз. Например, «большая пушка» системных администраторов «perl», как:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; rename $_,$n unless($_ eq $n || -e $n)'
что будет переименовывать все файлы, что выводит findв одном исполнении - например, намного быстрее, чем тысячи mvвыполнений.
Тестирование Tor (DRY RUN) использует следующее:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; print qq{old:$_ new:$n\n} unless($_ eq $n || -e $n)' #print instead of the rename
PS: Perl достаточно мощный, чтобы обрабатывать все сам, например. команда find тоже, но это более сложная тема ...
PS2: мой английский намного хуже моего bash, так что кто-то может отредактировать этот пост для добавления / исправления вещей ..;)