Переименование файлов рекурсивно в sh

Я использую Synology для хранения фильмов с камер видеонаблюдения. После копирования файла из системы CCTV в Synology я конвертирую его в формат AVI. Итак, у моих файлов есть такие имена:

10.01.07-10.01.48[M][@0][0].dav.avi 

Я хочу переименовать его рекурсивно из имен, подобных выше, для таких имен:

 10.01.07-10.01.48.avi 

Обратите внимание, что каждое имя файла состоит из одной и той же части [M][@0][0].dav.avi

Но проблема в том, что в оболочке Synology нет команды rename (это не будет bash )

Я пытался использовать команду find во многих разных синтаксисах, но безуспешно. Можете ли вы помочь мне найти решение?

4 Solutions collect form web for “Переименование файлов рекурсивно в sh”

Вы можете сделать:

 find . -name '*\[M]\[@0]\[0].dav.avi' -type f -exec sh -c ' for file do echo mv "$file" "${file%"[M][@0][0].dav.avi"}.avi" done' sh {} + 

(удалите echo если все будет хорошо).

Или если вы хотите переименовать все .dav.avi в .avi , но также удалить [M][@0][0] если есть:

 find . -name '*.dav.avi' -type f -exec sh -c ' for file do new=${file%.*.*} new=${new%"[M][@0][0]"}.avi echo mv "$file" "$new" done' sh + 

Это синтаксис POSIX, а также работа с утилитами busybox, поэтому он должен работать на синологии.

Несколько заметок (основанных на наблюдениях ваших собственных и других ответов):

  • шаблон, переданный в find -name должен быть процитирован, иначе он может быть расширен оболочкой.
  • вы не можете использовать xargs для имен файлов, если вы не можете гарантировать, что эти имена файлов не будут содержать пробелы или символы новой строки или кавычки или обратную косую черту.
  • Используйте printf вместо echo для вывода произвольных данных .
  • Оставляя переменное расширение без кавычек в контексте списка, имеет особое значение . Вы не хотите делать это здесь.
  • . character является специальным оператором регулярного выражения, вам нужно избегать его в регулярных выражениях, если вы хотите, чтобы его обрабатывали буквально.
  • Синтаксис для чтения строки с read – это строка IFS= read -r line , но опять же нет гарантии, что путь к файлу будет состоять только из одной строки.
  • Часто бывает лучше делать (cd -P -- "$dir" && find . ... -exec) чем find -- "$dir" ... -exec потому что он избегает проблем с значениями $dir которые оказываются find предикаты или начинаются с - и потому, что он сокращает путь к файлу, переданный в -exec и, таким образом, позволяет передавать больше.

Вот быстрое решение, использующее sed для переименования файлов:

 echo "10.01.07-10.01.48[M][@0][0].dav.avi" | sed 's/\[.*dav//' 10.01.07-10.01.48.avi 

Я ничего не знаю об оболочке Synology, но надеюсь, что sed доступен!

Используйте (например) в цикле:

 #!/bin/sh for file in *avi; do newName=$(echo "$file" | sed 's/\[.*dav//') mv -v "$file" "$newName" done 

До:

 ls 09.01.07-13.11.48[M][@0][0].dav.avi 110.01.07-13.11.48[M][@0][0].dav.avi 12.01.07-13.11.48[M][@0][0].dav.avi 

Запуск скрипта:

 ./renameAvi.sh ”09.01.07-13.11.48[M][@0][0].dav.avi” -> ”09.01.07-13.11.48.avi” ”110.01.07-13.11.48[M][@0][0].dav.avi” -> ”110.01.07-13.11.48.avi” ”12.01.07-13.11.48[M][@0][0].dav.avi” -> ”12.01.07-13.11.48.avi” 

После:

 ls 09.01.07-13.11.48.avi 12.01.07-13.11.48.avi 110.01.07-13.11.48.avi 

Изменить: если вы хотите использовать find один из способов реализации – это как в этом oneliner:

 find . -name "*.avi" | while read fileName; do newName=$(echo "$fileName" | sed 's/\[.*dav//'); mv -v "$fileName" "$newName"; done ”./01.01.07-13.11.38[M][@0][0].dav.avi” -> ”./01.01.07-13.11.38.avi” ”./01.01.07-13.11.39[M][@0][0].dav.avi” -> ”./01.01.07-13.11.39.avi” 

 sed --version sed (GNU sed) 4.2.2 find --version find (GNU findutils) 4.4.2 

Для переименования рекурсивных файлов вы должны использовать команду ниже.

 find . -name "*dav.avi" | while read fileName; do newName=$(echo "$fileName" | sed 's/\[.*dav//'); mv -v "$fileName" "$newName"; done 

Измените сценарий выше

(Я не мог добавить комментарий выше, поэтому добавление ответа здесь с небольшим изменением в скрипте, о котором уже говорилось в maulinglawns)

  • Используйте для поиска * dav.avi, так как у вас будет много рекурсивных файлов в вашем хранилище Synology, поэтому, как только эти файлы будут переименованы, это должно быть сделано снова.
  • Это очень небольшое изменение, но будет действовать, если ваша фактическая система ~ GBs файлов данных.

Наконец я нашел решение. Переименование выполняется в два этапа. Это связано с тем, что другие записывающие устройства CCTV могут передавать файлы с разными именами, но всегда в формате DAV. Таким образом, просто добавив дополнительную строку, похожую на вторую, позволит работать с другими типами рекордеров:

 find $katalog -type f -name *.dav.avi | sed -e "p;s/.dav.avi/\.avi/" | xargs -n2 mv 2>/dev/null find $katalog -type f -name *.avi | sed -e "p;s/\[M\]\[@0\]\[0\].avi/\.avi/" | xargs -n2 mv 2>/dev/null 
  • Преобразовать .out файл в .pdf с помощью сценария оболочки
  • Невозможно запустить сценарий tmux при загрузке
  • bash: проверьте, находится ли переменная в
  • Объединение двух разных файлов с условиями
  • Скрипт для запуска приложения с выделенной графической картой (Fedora 25)
  • Как мне ожидать «echo -e»? \ С»?
  • Помощь с 64-битными целыми числами в скриптах?
  • Преодоление новых строк с помощью grep -o
  • Загрузка нескольких похожих URL-адресов с использованием скобок
  • bash эквивалент zsh $ @
  • xdotool печатает 8 вместо Tab
  • Как использовать printf и% s при наличии цветовых кодов?
  • Interesting Posts

    Разделить разделенный запятыми список, игнорирующий запятые в соответствии с {}

    Как отключить горизонтальную прокрутку трекпада

    Почему режим текстового режима медленно прокручивается?

    Ищете простой графический уведомитель в KDE, invokable from bash

    Частично дублированная история при настройке PS1 в .bash_profile

    Управление управляющими символами в cron / mailx

    Почему я не могу выполнить «обновление sudo apt-get»?

    find {} возвращает полное имя файла, но я просто хочу имя файла без расширения, поэтому index.md вернет индекс вместо index.md

    IPv6, dnsmasq dhcp-range

    Arch Linux – Wi-Fi продолжает отключать

    Являются ли эти номера пропускной способности типичными для SSD?

    Каков размер физического сектора для моего жесткого диска?

    смонтировать диск во FreeBSD для редактирования файла, используя live CD

    Как окончательно отключить Ctrl-s в терминале?

    передавая переменные от 'ls' до 'tar' через 'xargs'

    Linux и Unix - лучшая ОС в мире.