Ответы:
Переносимый способ (который будет работать на любой POSIX-совместимой системе):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
В bash4 вы можете использовать globstar для получения рекурсивных глобусов (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Команда (perl) renameв Ubuntu может переименовывать файлы, используя синтаксис регулярных выражений perl, который вы можете комбинировать с globstar или find:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Также см. Http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c первым аргументом назначается $ 0, а все остальные аргументы назначаются позиционным параметрам . Таким образом, _аргумент является фиктивным, а '{}' - первым позиционным аргументом для sh -c.
Это сделает необходимую задачу, если все файлы находятся в одной папке
rename 's/.abc$/.edefg/' *.abc
Чтобы переименовать файлы рекурсивно, используйте это:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcв современной версии Bash.
sв начале, и какие другие варианты я могу использовать там. Спасибо !
Одна проблема с рекурсивными переименованиями состоит в том, что какой бы метод вы ни использовали для поиска файлов, он передает весь путь rename, а не только имя файла. Это затрудняет выполнение сложных переименований во вложенных папках.
Я использую find«s -execdirдействия , чтобы решить эту проблему. Если вы используете -execdirвместо -exec, указанная команда запускается из подкаталога, содержащего соответствующий файл. Таким образом, вместо того, чтобы пройти весь путь rename, он только проходит ./filename. Это значительно облегчает написание регулярного выражения.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
В деталях:
-type f означает только искать файлы, а не каталоги-name '*.abc' означает совпадение только с именами файлов, заканчивающимися на .abc'{}'это заполнитель, который отмечает место, куда -execdirбудет вставлен найденный путь. Одинарные кавычки необходимы, чтобы позволить ему обрабатывать имена файлов с пробелами и символами оболочки.-typeи -nameявляются символом продолжения строки bash. Я использую их, чтобы сделать этот пример более читабельным, но они не нужны, если вы поместите свою команду в одну строку.-execdirстроки обязательна. Это здесь, чтобы избежать точки с запятой, которая завершает команду, которой управляет -execdir. Веселье!Объяснение регулярного выражения:
s/ начало регулярного выражения\.\/соответствует ведущему ./, который передается в -execdir. Используйте \ для выхода из. и / метасимволы (примечание: эта часть зависит от вашей версии find. См. комментарий пользователя @apollo)(.+)соответствовать имени файла. Скобки фиксируют совпадение для последующего использования.\.abc избежать точки, сопоставить азбуку$ закрепить совпадение в конце строки
/ отмечает конец части регулярного выражения "match" и начало части "replace"
version1_ добавить этот текст к каждому имени файла
$1ссылается на существующее имя файла, потому что мы захватили его в скобках. Если вы используете несколько наборов скобок в части «match», вы можете ссылаться на них здесь, используя $ 2, $ 3 и т. Д..abcимя нового файла будет заканчиваться на .abc. Нет необходимости экранировать метасимвол точки здесь, в разделе «заменить»/ конец регулярного выраженияДо
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
После
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Подсказка: renameопция -n полезна. Он выполняет пробный прогон и показывает, какие имена он изменит, но не вносит никаких изменений.
--execdirначале не проходит, ./поэтому \.\/часть в регулярном выражении может быть опущена. Может это потому, что я на OSX, а не на Ubuntu
Еще один портативный способ:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Также смотрите запись о том, почему вы не должны анализировать ls.
Редактировать: если вам нужно использовать базовое имя, ваш синтаксис будет:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
Это то, что я делал и работал довольно так, как я хотел. Я использовал mvкоманду. У меня было несколько .3gpфайлов, и я хотел переименовать их все.mp4
Вот короткий вкладыш для этого:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Который просто просматривает текущий каталог, выбирает все файлы .3gp, затем переименовывает (используя mv) в ren-name_of_file.mp4
file.3gpв file.3gp.mp4, что может быть не то, что большинство людей хотят.
.3gpили .mp4только для иллюстрации.
basename "$i" .mp4предыдущее расширение вместо «ren- $ i.mp4».
Переименовать файлы и каталоги с find -execdir | rename
Если вы собираетесь переименовывать как файлы, так и каталоги не просто с помощью суффикса, тогда это хороший шаблон:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
В отличие от этого, потрясающая -execdirопция делает cdв каталог перед выполнением renameкоманды -exec.
-depth убедитесь, что переименование происходит сначала для детей, а затем для родителей, чтобы предотвратить потенциальные проблемы с отсутствующими родительскими каталогами.
-execdir требуется, потому что переименование плохо работает с путями ввода неосновного имени, например, следующие ошибки:
rename 's/findme/replaceme/g' acc/acc
PATHХакерство требуется , потому что -execdirимеет один очень досадный недостаток: findкрайне самоуверенный и отказывается что - либо делать с , -execdirесли у вас есть какие - либо относительные пути в вашем PATHпеременном окружении, например ./node_modules/.bin, в противном случае с:
find: Относительный путь «./node_modules/.bin» включен в переменную среды PATH, которая небезопасна в сочетании с действием -execdir команды find. Пожалуйста, удалите эту запись из $ PATH
-execdirявляется расширением GNU find для POSIX . renameоснован на Perl и поставляется из renameпакета. Проверено в Ubuntu 18.10.
Переименовать обходное решение
Если ваши входные пути не взяты find, или если вам надоело относительное раздражение пути, мы можем использовать некоторые возможности Perl для безопасного переименования каталогов, как в:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Я не нашел удобный аналог для -execdirс xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
sort -rТребуется для того , чтобы файлы приходят после их соответствующих каталогов, так как более длинные пути приходят после того, как более короткие, с тем же префиксом.