Відповіді:
Портативний спосіб (який буде працювати в будь-якій системі, сумісній з 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
є символом продовження баш-лінії. Я використовую їх, щоб зробити цей приклад більш читабельним, але вони не потрібні, якщо ви поставите свою команду в один рядок.-execdir
рядка потрібен. Саме там можна уникнути крапки з комою, яка закінчує команду, яку виконує -execdir
. Весело!Пояснення регулярного вираження:
s/
початок регулярного виразка\.\/
відповідати ведучому ./, який передає -execdir. Використовуйте \, щоб уникнути. та / метахарактеристики (зверніть увагу: ця частина залежить від вашої версії find
. Див. коментар користувача @apollo)(.+)
відповідати імені файлу. Дужки фіксують збіг для подальшого використання\.abc
втекти крапкою, відповідати абс$
закріпіть сірник в кінці рядка
/
позначає закінчення «збіжної» частини регулярного вираження та початок частини «заміни»
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
's -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 пошуку. Видаліть цей запис із $ PATH
Дивіться також: Чому використання дії "-execdir" небезпечно для каталогу, який знаходиться в PATH?
-execdir
є розширенням пошуку GNU до 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
Потрібно для того , щоб файли приходять після їх відповідних каталогів, так як більш довгі шляхи приходять після того, як більш короткі, з тим же префіксом.