Массовое переименование файлов на камкордерах, включая пробелы

Я пытаюсь переименовать пакетные имена с именами, отмеченными на верблюжьих именах, чтобы включить пробелы между соседними верхними и нижними регистрами. Я использую Mac OS, поэтому утилиты, которые я использую, являются BSD-вариантом.

Например:

250 - ErosPhiliaAgape.mp3 => 250 - Eros Philia Agape.mp3 

Я пытаюсь find соответствующие файлы и передать их в mv который запускает sed в подоболочке, используя эту команду:

 find . -name "*[az][AZ]*" -print0 | xargs -0 -I {} mv {} "$(sed -E 's/([az])([AZ])/\1 \2/g')" 

Индивидуально эти команды работают нормально: find вытаскивает правильные файлы, а sed переименовывает их правильно, но когда я их совмещаю с xargs, ничего не происходит.

Что мне нужно изменить, чтобы сделать эту работу?

3 Solutions collect form web for “Массовое переименование файлов на камкордерах, включая пробелы”

Проблема в том, что xargs $(...) в вашей команде оценивается в момент запуска этой команды и не оценивается xargs для каждого файла. Вы могли бы использовать find -exec вместо того, чтобы оценивать команды для каждого файла в sh , а также соответствующим образом заменять цитирование:

 find . -name "*[az][AZ]*" -type f -exec sh -c 'echo mv -v "{}" "$(echo "{}" | sed -E "s/([az])([AZ])/\1 \2/g")"' \; 

Если результат этого выглядит неплохо, отбросьте echo в echo mv . Обратите внимание, что из-за echo | sed echo | sed , это не будет работать с именами файлов со встроенным \n . (Но это было уже существующее ограничение в вашей собственной попытке, поэтому я надеюсь, что это приемлемо.)

Ваша команда sed принимает входные данные из трубы. Он конкурирует с xargs , поэтому каждая из двух команд получит часть данных, записанных find (каждый байт переходит только к одному читателю), и это непредсказуемо, что получает что.

Вам нужно будет связать каждое имя файла с sed , что означает, что вам нужна промежуточная оболочка для настройки канала.

 find . -name "*[az][AZ]*" -print0 | xargs -0 -I {} sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([az])([AZ])/\1 \2/g'\'')"' {} 

Вам не нужны xargs , это в основном бесполезно. find может вызвать программу напрямую.

 find . -name "*[az][AZ]*" -exec sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([az])([AZ])/\1 \2/g'\'')"' {} \; 

Кроме того, установите любую из реализаций rename Perl, например File::Rename или одну из Unicode::Tussle .

 cpan File::Rename find -depth . -exec rename 's!([az])([AZ])(?!.*/)!$1 $2!g' {} + 

Бит (?!.*/) Запрещает замену от запуска в именах каталогов, если они содержат видеокамеру. Передача -depth для find гарантирует, что если каталог переименован, это произойдет после find как find переместит его.

Если вы предпочитаете использовать GNU Parallel, это решение:

 find . -name "*[az][AZ]*" -type f | parallel mv -v {} '{= s:([az])([AZ])(?!.*/):$1 $2:g =}' 
  • почему вывод xargs -n2 применяется к тому же количеству аргументов, различающихся по каналам или с клавиатуры?
  • find: несколько `-exec` с условиями
  • Сортировка вывода «find»?
  • Как выполнить выходную строку без замены команды bash?
  • xargs не работает в Linux, поскольку работает в Unix
  • xargs - добавить каждый аргумент с параметром
  • Как копировать рекурсивно все файлы не старше 1 дня?
  • Различное поведение между find -exec и piping через xargs
  • Как найти и скопировать файлы на основе расширения?
  • Найти файлы рекурсивно, которые старше одного года и не принадлежат конкретному пользователю
  • Как создать бесконечный поток строк в bash
  • Linux и Unix - лучшая ОС в мире.