Ответы:
Переносимый способ (который будет работать на любой 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
Требуется для того , чтобы файлы приходят после их соответствующих каталогов, так как более длинные пути приходят после того, как более короткие, с тем же префиксом.