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


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.