Сам вопрос тоже не точный, потому что ФП говорит о:
- имена файлов вроде
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
, так что кто-то может отредактировать этот пост для добавления / исправления вещей ..;)