Как переименовать несколько файлов, заменив строку в имени файла? эта строка содержит «#»

43

https://serverfault.com/questions/70939/how-to-replace-a-text-string-in-multiple-files-in-linux

https://serverfault.com/questions/228733/how-to-rename-multiple-files-by-replacing-word-in-file-name

https://serverfault.com/questions/212153/replace-string-in-files-with-certain-file-extension

https://serverfault.com/questions/33158/searching-a-number-of-files-for-a-string-in-linux

Эти упомянутые статьи все ответили на мой вопрос. Однако ни один из них не работает для меня. Я подозреваю, что это потому, что строка, которую я пытаюсь заменить, содержит #. Есть ли особый способ решения этой проблемы?

У меня есть файл изображения, который заменил é на # U00a9 во время миграции сайта. Это выглядит так:

Lucky-#U00a9NBC-80x60.jpg
Lucky-#U00a9NBC-125x125.jpg
Lucky-#U00a9NBC-150x150.jpg
Lucky-#U00a9NBC-250x250.jpg
Lucky-#U00a9NBC-282x232.jpg
Lucky-#U00a9NBC-300x150.jpg
Lucky-#U00a9NBC-300x200.jpg
Lucky-#U00a9NBC-300x250.jpg
Lucky-#U00a9NBC-360x240.jpg
Lucky-#U00a9NBC-400x250.jpg
Lucky-#U00a9NBC-430x270.jpg
Lucky-#U00a9NBC-480x240.jpg
Lucky-#U00a9NBC-600x240.jpg
Lucky-#U00a9NBC-600x250.jpg
Lucky-#U00a9NBC.jpg

и я хочу изменить это на что-то вроде этого:

Lucky-safeNBC-80x60.jpg
Lucky-safeNBC-125x125.jpg
Lucky-safeNBC-150x150.jpg
Lucky-safeNBC-250x250.jpg
Lucky-safeNBC-282x232.jpg
Lucky-safeNBC-300x150.jpg
Lucky-safeNBC-300x200.jpg
Lucky-safeNBC-300x250.jpg
Lucky-safeNBC-360x240.jpg
Lucky-safeNBC-400x250.jpg
Lucky-safeNBC-430x270.jpg
Lucky-safeNBC-480x240.jpg
Lucky-safeNBC-600x240.jpg
Lucky-safeNBC-600x250.jpg
Lucky-safeNBC.jpg

ОБНОВИТЬ:

Все эти примеры начинаются с "LU00a9ucky", но здесь много изображений с разными именами. Я просто нацеливаюсь на часть строки "# U00a9", чтобы заменить на "safe".

Сообщество
источник
3
Так что вы на самом деле пытались? Я вижу, что вы связались с несколькими вопросами и сказали, что они потерпели неудачу, но как они потерпели неудачу? ИМО лучший пример использует renameкоманду. Я подозреваю, что ваше переименование будет так же просто, как rename -n 's/#/safeNBC/' *.jpg.
Зоредаче
Я попытался, rename -n 's/#U00a9/safe/' *.jpgи команда была принята, но никаких изменений не произошло.
Конечно, как вы могли видеть из документации, которую вы наверняка просматривали, -nэто no actвариант. Что позволяет увидеть, работает ли оно до того, как вы его на самом деле используете. Правильно ли отображались выходные данные на экране?
Zoredache
Я прошу прощения, я скопировал и вставил ваш пример, не обращая полного внимания, я сделал команду переименования без -n. Я считаю, что @DTK решит проблему, я не избежал #.
Замена строк в именах файлов на MacOS: superuser.com/questions/152627/…
Антон Тарасенко

Ответы:

65

Для того, чтобы заменить #на somethingelseимена файлов в текущем каталоге (не рекурсивный) , вы можете использовать GNU переименования утилиты:

rename  's/#/somethingelse/' *

Символы вроде -должны быть экранированы с \.

Для вашего случая вы хотели бы использовать

rename 's/#U00a9/safe/g' *

Обратите внимание, что если вы хотите работать только с определенным набором файлов, например, только *.jpg, настройте окончательный ввод в соответствии с этим выбором:

rename 's/#U00a9/safe/g' *.jpg

Чтобы выполнить тест до фактического изменения имен файлов, используйте -nфлаг:

demo/> ls                               
Lucky-#U00a9NBC-125x125.jpg  
Lucky-#U00a9NBC-150x150.jpg 

demo/> rename -n 's/#U00a9/safe/g' *.jpg
rename(Lucky-#U00a9NBC-125x125.jpg, Lucky-safeNBC-125x125.jpg)
rename(Lucky-#U00a9NBC-150x150.jpg, Lucky-safeNBC-150x150.jpg)

Для OS X, GNU переименование может быть установлено с помощью доморощенного : brew install rename.

KrisWebDev
источник
Это не сработало на моей машине (Arch Linux), но ответ Мика сработал.
marcvangend
@marcvangend Какую версию renameвы используете? # sudo pacman -S perl-renameустановит Perl-версию, которая является более мощной и может быть достаточной для того, чтобы этот ответ работал для вас.
Джон Гауэрс
@JohnGowers Спасибо! Я не осознавал, что есть две версии. В моей системе rename --versionвозвращается rename from util-linux 2.29.2так, что это действительно не версия Perl.
marcvangend
5
Существует две общие renameутилиты, но ни одна из них не разработана GNU: дистрибутивы на основе Debian включают renameутилиту с пакетом Perl, а дистрибутивы на основе Red Hat используют renameутилиту из util-linuxорганизации ядра Linux. Ваша ссылка на функциюrename C из стандартной библиотеки GNU.
Энтони Дж - справедливость для Моники
2
В этом ответе, почему мы должны писать /gвrename 's/#U00a9/safe/g' *
Nikhil
24

найти список файлов, а затем заменить ключевое слово. ниже пример

find . -name '*jpg' -exec bash -c ' mv $0 ${0/\#U00a9NBC/safeNBC}' {} \;
Суджит Дхамале
источник
1
Вам нужны двойные кавычки вокруг ваших mvаргументов, если в названии есть пробелы
Стоп Харминг Моника
Мне нужно было заменить все файлы * _spec.rb на * _controller_spec.rb, и ваше решение сработало для меня. Thanx.
Джедай
Спасибо. Это решит мою проблему
Фабио Соуза
19

Это не сложно, просто убедитесь, что экранирования (#) в имени не используется, добавив обратную косую черту (\).

find . -type f -name 'Lucky-*' | while read FILE ; do
    newfile="$(echo ${FILE} |sed -e 's/\\#U00a9/safe/')" ;
    mv "${FILE}" "${newfile}" ;
done 
Сообщество
источник
Ваше объяснение имеет смысл, избегая #звуков, как то, что мне нужно. Я не вижу обратной косой черты в вашем примере. Должно ли это выглядеть так: s/\#U00a9/safe/
@LeonFrancisShelhamer хороший улов. Он проглотил обратную косую черту. Я изменю
17

Чтобы выйти #из оболочки, просто используйте одинарные кавычки ( '#'), двойные кавычки ( "#") или обратную косую черту ( \#).

В вашем случае проще всего использовать renameкоманду (если она доступна):

rename '#U00a9' safe *.jpg
МИК
источник
2
Спасибо. Хотя ответ с наибольшим количеством голосов ( rename 's/#/somethingelse/' *) не работал на моей машине (Arch Linux), этот работал.
Marcvangend
1
Это работает с помощью команды переименования из util-linux.
грязно
10

не знаю, как в sed, но вы можете попробовать это в оболочке bash:

for f in Lucky-#U00a9NBC-*.jpg; do mv -v "$f" "${f/#U00a9/safe}"; done;

объяснение:

  1. перебирает все имена файлов, соответствующие глобусу (Lucky- # U00a9NBC - *. jpg)
  2. переименовывает файл с помощью команды перемещения (mv)
  3. использует собственную подстановку параметров bash $ {var / Pattern / Replacement} для создания нового имени ("$ {f / # U00a9 / safe}")

Подробнее о замене параметров (в которой ИМО используется недостаточно): http://www.tldp.org/LDP/abs/html/parameter-substitution.html

Грегори Патмор
источник
Хотя этот код может ответить на вопрос, сам по себе он не очень полезен. Объяснение, как это решает проблему, улучшило бы полезность и долгосрочную ценность ответа.
Энтони Дж. - правосудие для Моники
добавлено объяснение прохождения и дальнейшее чтение согласно комментарию Энтони.
Грегори Патмор
1

Приведенные выше примеры не работали в моей системе (CentOS 5.6), поэтому я обнаружил (возможно, более специфичную для системы) команду, которая работает (примечание: необходимо экранировать «#» с помощью \командной строки):

rename \#U00a9 safe *.jpg

[Также: у меня недостаточно репутации, чтобы комментировать, поэтому в ответ на вопрос Нихила об использовании /g in rename 's/old_string/new_string/g'(поставлено в комментариях для другого ответа выше):

Используйте gмодификатор для выполнения «глобальной» замены (то есть для замены new_string на old_string столько раз, сколько происходит old_string). Это не должно быть необходимо в моем ответе, потому что renameон будет применен ко всем файлам, указанным в *. См. Https://www.computerhope.com/unix/rename.htm для краткого объяснения этого и других модификаторов.]

Эзра Цитрон
источник
Правильный; Производные от Fedora ОС, такие как CentOS, имеют другую версию, renameнежели производные от Debian. См. Unix.stackexchange.com/a/238862/135943 . И, кстати, CentOS 5.6 довольно старый, и я рекомендую вам обновить.
Wildcard
Ах, спасибо за объяснение + ссылка. Устаревшая ОС работает, поэтому мне не нужно обновлять :), но новый кластер создается, и, по-видимому, мы будем обновляться, когда мы переедем ...
Ezra Citron
0

Вот решение DTK, заключенное в многоразовую функцию bash:

function renameFilesRecursively () {

  SEARCH_PATH="$1"
  SEARCH="$2"
  REPLACE="$3"

  find ${SEARCH_PATH} -type f -name "*${SEARCH}*" | while read FILENAME ; do
      NEW_FILENAME="$(echo ${FILENAME} | sed -e "s/${SEARCH}/${REPLACE}/g")";
      mv "${FILENAME}" "${NEW_FILENAME}";
  done

}

Вот как вы можете использовать это:

renameFilesRecursively /home/user/my-files apple orange
Слава Фомин II
источник
0

На самом деле renameесть опция именно для того, чтобы звонили --substили -sкороче. Нет необходимости использовать синтаксис регулярных выражений.

rename -s '#U00a9' 'safe' *

Если вы хотите заменить / заменить несколько вхождений, используйте --subst-allили -S.

Кстати, я хотел только заменить строку ничем (удалить ее из имени файла) ... ну, у нас также есть возможность для этого -d/--deleteи -D/--delete-all:

rename -d '#U00a9' *
кроличий мех
источник
-1

Другим вариантом является использование pyRenamerприложения, созданного специально для пакетного переименования.

Может быть установлен с sudo apt-get install pyrenamer

Подробнее об использовании см. В файле README на GitHub .

Сайна Т
источник
1
Если вы действительно думаете, что это может ответить на вопрос, пожалуйста, добавьте пояснения к вашему ответу. Само по себе, он только устанавливает пакет. Вы должны объяснить, что делает команда, и предоставить пример, который обрабатывает специфические требования OP.
Ройма