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


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

Некоторые идеи на 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"
сделанный

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

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

Ответы здесь, на которые ссылаются 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

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+.
— Деннис Голомазов


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/' \{} \;

1
ПОЖАЛУЙСТА, добавьте. перед «текстом»
— danielmhanover

2

Когда ты

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

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

for f in *; do mv -- "$f" "${f%.\*}.text"; done

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.