Как изменить репликацию расширения нескольких файлов из командной строки?

62

У меня есть много файлов с расширением .abc и хочу изменить их на .edefg
Как это сделать из командной строки?

У меня есть корневая папка со многими подпапками, поэтому решение должно работать рекурсивно.

    
задан tommyk 19.04.2011 в 14:02
источник

8 ответов

78

Портативный способ (который будет работать в любой 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/' {} +

Также см. Ссылка

    
ответ дан geirha 19.04.2011 в 20:51
37

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

rename 's/.abc$/.edefg/' *.abc

Для переименования файлов рекурсивно используйте это:

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
    
ответ дан Chakra 19.04.2011 в 14:23
11

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

Я использую find -execdir для решения этой проблемы. Если вы используете -execdir вместо -exec , указанная команда запускается из подкаталога, содержащего сопоставленный файл. Таким образом, вместо передачи всего пути к rename он пропускает только ./filename . Это облегчает запись регулярного выражения.

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;

Подробнее:

  • -type f означает только поиск файлов, а не каталогов
  • -name '*.abc' означает означает только совпадение имен файлов, которые заканчиваются на .abc
  • Обратные косые черты после -type и -name являются символом продолжения строки bash. Я использую их, чтобы сделать этот пример более читабельным, но на практике они не нужны.
  • Однако обратная косая черта в конце строки -execdir требуется. Здесь есть esacpe точка с запятой, которая завершает команду, выполняемую -execdir . Fun!

Объяснение регулярного выражения:

  • s/ начало регулярного выражения
  • \.\/ соответствует ведущему ./, который проходит -execdir. Используйте \, чтобы избежать. и / метасимволы
  • (.+) соответствует имени файла. Скобки заключают совпадение для последующего использования.
  • \.abc удаляют точку, соответствуют abc
  • $ привязать совпадение в конце строки

  • / обозначает конец части «соответствия» регулярного выражения и начало «замены»

  • version1_ добавить этот текст в каждое имя файла

  • $1 ссылается на существующее имя файла, потому что мы зафиксировали его в круглых скобках. Если вы используете несколько наборов круглых скобок в части «match», вы можете обратиться к ним здесь, используя $ 2, $ 3 и т. Д.
  • .abc имя нового файла закончится на .abc. Нет необходимости избегать метасимвола точки здесь, в разделе «replace».
  • / конца регулярного выражения

Перед

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 полезна. Он выполняет сухой запуск и показывает вам, какие имена он изменит, но не вносит никаких изменений.

    
ответ дан Christian Long 06.10.2012 в 00:48
5

Другой переносной способ:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
    
ответ дан aNeutrino 03.02.2013 в 17:36
0
# Rename all *.txt to *.text
for f in *.txt; do 
mv -- "$f" "${f%.txt}.text"
done

Также см. запись о том, почему вы не должны анализировать ls .

Изменить: если вам нужно использовать basename, ваш синтаксис будет выглядеть следующим образом:

for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done

Ссылка

    
ответ дан ashanrupasinghe 22.08.2016 в 14:12
0

Это то, что я сделал и работал довольно просто так, как я хотел. Я использовал команду mv . У меня было несколько% файлов co_de%, и я хотел переименовать их все в .3gp

Вот короткая строка для него:

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

Что просто просматривает текущий каталог, забирает все .3gp-файлы, а затем переименовывает (используя mv) в .mp4

    
ответ дан Rexford 13.03.2016 в 22:58
0

Я нашел простой способ добиться этого. Чтобы изменить расширения многих файлов с jpg на pdf, используйте:

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
    
ответ дан Peaceful 27.09.2017 в 05:39
0

Я бы использовал команду mmv из пакета с таким же именем :

mmv ';*.abc' '#1#2.edefg'

; соответствует нулю или более */ и соответствует замене #1 . * соответствует #2 . Нерекурсивная версия будет

mmv '*.abc' '#1.edefg'
    
ответ дан MvG 20.05.2018 в 23:13