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

168

Я хотел бы изменить расширение файла с *.txtна *.text. Я попытался использовать basenameкоманду, но у меня возникают проблемы при изменении более одного файла.

Вот мой код:

files=`ls -1 *.txt`

for x in $files
do
    mv $x "`basename $files .txt`.text"
done

Я получаю эту ошибку:

basename: too many arguments Try basename --help' for more information
afbr1201
источник
Некоторые идеи на peteryu.ca/tutorials/shellscripting/batch_rename тоже
Nemo

Ответы:

176

Прямо из Вики Грега :

# Переименовать все * .txt в * .text
для f в * .txt; делать
    mv - "$ f" "$ {f% .txt} .text"
сделанный

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

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

для f в * .txt; делать
    mv - "$ f" "$ (basename -" $ f ".txt) .text"
сделанный
jasonwryan
источник
48
Здесь есть немного продвинутый синтаксис Bash, используемый здесь без объяснения причин. Мне пришлось Google много вещей, чтобы понять это полностью. Для того, чтобы помочь другим в моем положении, вот некоторые ссылки о комках ( *.txtсинтаксис) , на голой двойной дефис-- , и использование символа% в ${}конструкции . До сих пор я никогда не сталкивался с последними двумя и не знал, что на самом деле происходит с первым.
Марк Амери
3
Посмотрите на ответ Матиаса Брауна ниже - он намного проще, выполняет то же самое.
БТ
10
Один лайнерfor f in *.txt; do mv -- "$f" "${f%.txt}.text"; done
Марсал Хуан
1
Вы пропали без вести; после текста ".
Петур Инги
2
@ PéturIngiEgilsson на второй линии? Нет, это не обязательно.
Джейсонвриан
133

Вот как я могу изменить все расширения файлов в текущем каталоге Debian.

rename "s/oldExtension/newExtension/" *.txt

(Это команда Perl rename, а не util-linuxта. См. Почему утилита переименования в Debian / Ubuntu отличается от утилиты в других дистрибутивах, таких как CentOS? )

Матиас Браун
источник
10
Гораздо проще, чем принятый ответ, спасибо!
БТ
8
На Mac я смог brew install renameи заставить это работать.
Monkpit
3
с помощью shell рыбы вы можете сделать rename "s/oldExtension/newExtension/" **.txtрекурсивное переименование всех * .txt
Palmstrom
3
Это не удастся для footxt.txt. Используйте это вместо: unix.stackexchange.com/questions/19654/…
wisbucky
7
Если ваши файлы не имеют расширения и вы хотите добавить его:rename 's/$/.txt/' *
mkataja
35

Простая команда, renamefromutil-linux , сделает это за вас, она заменит все «txt» на «text» во всех файлах, соответствующих «* .txt»:

rename txt text *.txt
lamwaiman1988
источник
4
renameизменяет первое вхождение, так что лучше сделайте это rename .txt .text, но это все равно не всегда будет работать (например, оно переименовывается foo.txtx.bar.txtв foo.textx.bar.txt).
Жиль
12
Следует отметить, что не все системы имеют одинаковую версию переименования; на Debian и в друзьях renameкоманда на самом деле perl-renameиспользует регулярные выражения perl. Для этого, эквивалентная команда будет: rename 's/.txt/.text/' *.txt. Люди должны проверить man renameсвою систему, чтобы узнать, какая у них есть.
evilsoup
@evilsoup Это случай для OSX, спасибо
Дэви Лима
Это также работает на Cygwin (Windows)
Энди
27
rename "s/oldExtension/newExtension/" *.txt

Выше работает нормально, но ограничивается текущим каталогом. Попробуйте команду ниже, которая является гибкой с подкаталогами. Он переименует все .txtфайлы в структуре каталогов с новым расширением.

find . -name "*.txt" -exec rename 's/.txt$/.newext/' {} \;
Рахул
источник
2
renameможет обрабатывать несколько файлов в качестве аргумента, вы можете значительно ускорить процесс, используя +вместо того, \;чтобы их было много
Anthon
Тем не менее, это полезный параметр, поскольку "* .txt" может развернуть большой список аргументов, не поддерживаемый оболочкой.
Роман Шаповалов
1
«s / oldExtension / newExtension /» не будет работать для footxt.txt. Используйте это вместо: unix.stackexchange.com/questions/19654/…
wisbucky
9
for f in *.txt
do
    [ -f "$f" ] && mv "$f" "${f%txt}text"
done
Принц Джон Уэсли
источник
9

Ответы здесь, на которые ссылаются s/oldExtension/newExtension/, неверны. Если вы используете s/txt/text/, вы бы конвертировать footxt.txtв footext.txt, который не то , что вы хотите. Даже если вы используете s/.txt/.text/, это будет преобразовано footxt.txtв fo.text.txt.

Вы должны использовать, \.чтобы соответствовать периоду ( .будет соответствовать любой символ). И трейлинг, $чтобы соответствовать концу строки. Только это будет правильно соответствовать расширению.

rename 's/\.txt$/.text/' *.txt

rename 's/\.old$/.new/' *.old
wisbucky
источник
7

Основываясь на ответе @Prince John Wesley, вот простой bash-скрипт для изменения всех расширений файлов в текущем каталоге с ext1на ext2. Также выводит имена переименованных файлов.

#!/bin/bash
for f in *.$1
do
    [ -f "$f" ] && mv -v "$f" "${f%$1}$2"
done

Пример использования (при условии, что имя скрипта таково change-ext):

change-ext ext1 ext2
Денис Голомазов
источник
Для рекурсивного изменения расширений файлов в каталогах замените вторую строку ( for...) двумя строками: shopt -s globstarи for f in **/*.$1. Требуется Bash 4+.
Деннис Голомазов
4

Причина № 53 для перехода на Zsh:

zmv '(*).txt' '$1.text'

Benitok
источник
3

скажем, ваши файлы разбросаны по разным каталогам. Предполагая, что dirx является вашим родительским каталогом, это можно сделать с помощью команды find:

for f in `find /dirx -iname '*.txt' -type f -print`;do  mv "$f" ${f%.txt}.text; done
Сыпь
источник
Как насчет tcsh ..
Йозеф Климук
2

Это то, что работает для меня:

find . -name '*.txt' -exec rename 's/\.txt$/.text/' \{} \;
yegor256
источник
1
ПОЖАЛУЙСТА, добавьте. перед «текстом»
danielmhanover
2

Когда ты

не имеют расширения для исходных файлов

и целевое расширение .text, вы бы сделали это следующим образом -

for f in *; do mv -- "$f" "${f%.\*}.text"; done
nitinr708
источник
1
Отличный bash-native скрипт. работал отлично! for f in *.html; do mv -- "$f" "${f%.\*}.pug"; done
TamusJRoyce
1

Если вы хотите узнать, что пошло не так в вашей версии: вы использовали $filesвместо $xнее команду basename. Так что это должно работать (хотя и не проверено):

for x in *.txt
do
  mv "$x" "`basename '$x' .txt`.text"
done
Даниэль Куллманн
источник