Пакетное переименование файлов, которые заканчиваются точкой

У меня большой файловый сервер Unix, с одним большим общим ресурсом SMB. Он обслуживает клиенты Mac, Linux и Windows. Большая часть файлов в этом окне была перенесена туда с Mac Xserve. Одним из способов резервного копирования общего ресурса является окно Windows. Это конкретное программное обеспечение резервного копирования дает сбой, если в именах файлов есть символы, которые ему не нравятся.

Мне удалось исправить большинство проблем с именами файлов, но я борюсь с файлами, которые заканчиваются точкой. Например:

  • filename.
  • newfile.txt.
  • stupid old file.

Я пытаюсь найти способ пакетного переименования всех файлов, которые заканчиваются на точку с тем же именем без точки. Так filename. становится filename

find . -name "*."

работает, чтобы найти файлы. Я попытался передать его через sed:

find . -name "*." | sed 's/.$//'

который выполняет работу в консоли, но фактически не переименовывает файлы. Это та часть, с которой я борюсь.

3 ответа

Если у вас есть версия сценария Perl rename (называется либо rename или же prename):

rename 's/\.$//' *.

или версия util-linux (называется rename или же rename-ul):

 rename . '' *.

Если вы запустите команду без аргументов и получите что-то похожее на:

Использование: переименовать [-v] [-n] [-f] perlexpr [имена файлов]

тогда это версия сценария Perl.

Что-то вроде:

rename.ul: недостаточно аргументов

Использование: rename.ul [опции] файл замены выражения...

Опции: -v, --verbose объяснить, что делается -V, --version
вывести информацию о версии и выйти -h, --help показать эту справку и выйти

означает, что это версия util-linux.

Похоже, что это должно сделать работу:

find . -type f -name '*\.' -exec bash -c 'mv "$1" "${$1%.}"' _ {} \;

Это ограничивает поиск только файлами с точкой в ​​конце (в противном случае он соответствует текущему рабочему каталогу, '.'), А затем выполняет приведенный фрагмент оболочки (mv "$1" "${$1%.}") для каждого имени файла, который он находит. Во фрагменте оболочки он использует расширение и подстановку параметров bash для удаления завершающего символа '.'. Другой шум строки в конце необходим для поиска -exec: {} это совпадающий текст из находки, \; требуется завершить строку exec, и я считаю, _ говорит exec передать {} в качестве параметра ($1) к sh команда. Если честно, это конкретное использование -exec для меня в новинку, я нашел его здесь.

Бит замещения bash довольно прост, и я часто использую его для переименования файлов, например FILENAME=foo.JPG; mv ${FILENAME} ${FILENAME%.JPG}.jpg удалит ".JPG" из FILENAME и заменит его на ".jpg"

Если вы все еще хотите использовать sed, а не bash, это выглядит так, как будто это сделает эту работу:

find . -type f -name '*\.' -exec sh -c 'mv "{}" "$(echo {} | sed s/\.$// )"' \;

Я сначала попытался решить эту проблему, не вызывая -exec вызывать sh -c, но это не понравилось расширению {} при попытке сделать sed (или с примером замены bash ранее).

Также обратите внимание, что вы должны поставить " " вокруг имен файлов, которые вы расширяете (например, {} или $1, в зависимости от примера), так как в ваших образцах файлов есть пробелы. Это может все еще сломаться в зависимости от того, какие специальные символы находятся в вашем файле (например, "в имени файла вызовет проблемы).

Вроде хак, но должно работать

Если вы хотите переименовать оба файла и каталоги с конечными точками:

    find . -name "*." -print0 | xargs -0 -n 1 my_rename.sh

ИЛИ, если вы хотите переименовать только файлы:

    find . -name "*." -type f -print0 | xargs -0 -n 1 my_rename.sh

где my_rename.sh скрипт просто:

#!/bin/bash
mv "$1" "${1%%.}"

(Также не забудьте сделать скрипт исполняемым: chmod +x my_rename.sh) 2

Другие вопросы по тегам