Как переименовать расширение для группы файлов?

480

В каталоге у меня есть куча *.htmlфайлов. Я хотел бы переименовать их всех в*.txt

Как я могу это сделать? Я использую оболочку bash.

bmw0128
источник

Ответы:

382

Для лучшего решения (с использованием только функций bash, в отличие от внешних вызовов) см. Один из других ответов .


Следующее будет делать и не требует, чтобы система имела renameпрограмму (хотя чаще всего это было бы в системе):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

РЕДАКТИРОВАТЬ: Как указано в комментариях, это не работает для имен файлов с пробелами в них без надлежащего цитирования (теперь добавлено выше). Когда вы работаете исключительно с вашими собственными файлами, у которых, как вы знаете, нет пробелов в именах файлов, это будет работать, но всякий раз, когда вы пишете что-то, что может быть использовано позже, не пропускайте правильное цитирование.

Микаэль Ауно
источник
47
Альтернатива, без базового имени и с кавычками: mv "$ {file}" "$ {file /%. Html / .txt}" (подробности см. В man bash, Расширение параметров)
Rodrigo Queiro
7
Конечно, только в том случае, если все файлы находятся в текущем каталоге, поскольку базовое имя удаляет часть пути. Просто будьте осторожны!
Джонатан Леффлер
6
Это плохое решение не только потому, что оно медленное, но и потому, что оно не работает с именами файлов с пробелами в них. Вы должны ВСЕГДА делать правильные цитаты в скриптах bash. mv "$ file" "$ (basename" $ ​​file ".html)". txt будет намного лучше. Но все же, mv "$ files" "$ {files% .html} .txt" намного лучше.
Balázs Pozsár
8
в окнах вы просто делаетеren *.a *.b
Мухаммед Умер
2
Как минимум, используйте POSIX-указанный $()вместо устаревшего синтаксиса обратного ключа. Улучшает читабельность и делает синтаксис намного менее двусмысленным, когда у вас есть символы, которые необходимо экранировать от обратной косой черты, чтобы быть буквальными внутри подстановки команд последней.
Чарльз Даффи
669

Если вы используете bash, вам не нужны внешние команды, такие как sed, basename, rename, expr и т. Д.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done
ghostdog74
источник
12
И если вы не знаете расширение файла, которое вы можете использовать "${file%.*}.txt", но это может быть опасно для файлов без расширения вообще.
Джесс
1
Примечание для тех, у кого возникли проблемы с тем, как это работает, как у меня: обратите внимание, что $внутри фигурных скобок нет!
doug65536
5
Мне нужен способ навсегда добавить в избранное / добавить в закладки этот ответ, я никогда не помню точный синтаксис, и в итоге я
ищу
7
@danip Конструкция знака процента внутри скобки удаляет символы с конца. Существует также конструкция хэш внутри скобки, которая удаляет символы с начала. Проверьте это: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
4
Другой ответ об обмене стека (который я не могу найти!) Предложил это, но также использовал --«operator»: mv - «$ file» «$ {file% .html} .txt» Этот оператор предотвращает имена файлов, начинающиеся с '-' от анализа mv в качестве аргументов.
rcreswick
191
rename 's/\.html$/\.txt/' *.html

делает именно то, что вы хотите.

янтарный
источник
Я не думаю, что вы можете использовать буквальное регулярное выражение в bash, как вы предлагаете - какую оболочку вы используете?
DaveR
1
я использую терминал Mac
bmw0128
Вот страница людей для версии переименования на Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Amber
переименовать это команда в некоторых системах. У меня есть Perl-скрипт (изначально из первой книги Camel), который делает эту работу. Есть также программа GNU с тем же именем, которая выполняет примерно ту же работу. Мой Mac не имеет предоставленной системой команды «переименовать» - или ее нет в моей переменной PATH (которая носит умеренный характер).
Джонатан Леффлер
В Homebrew есть формула переименования.
Revprez
112

Это работало для меня на OSX от .txt до .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
Стивен Лизаразо
источник
4
Прекрасно работает и в Linux.
Дизиет
Дело не в этом, но чтобы перейти .txtк .txt_bakвам, нужно просто _bak
объединить
3
Это хорошо для рекурсивного переименования
leachryanb
Большой! (в Ubuntu 16.04) Мой практический пример использования, переименование всех .scssв .sass(после преобразования на месте…):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Фрэнк Нок
2
это работало с файлами +6000, переименование сообщило, что «список аргументов был слишком длинным»
Тони Кронин,
94

Вы хотите использовать rename:

rename -S .html .txt *.html

Это делает именно то, что вы хотите - оно изменит расширение с .htmlна .txtдля всех подходящих файлов *.html.

Примечание: Грег Хьюгилл правильно указывает, что это не встроенная команда bash; и это отдельная команда Linux. Если вам просто нужно что-то в Linux, это должно работать нормально; если вам нужно что-то более кроссплатформенное, взгляните на один из других ответов.

Daver
источник
7
Хотя это хорошее решение, renameпрограмма не связана bashи не доступна на всех платформах. Я видел это только в Linux.
Грег Хьюгилл
15
«$ rename .html .txt * .html» приводит к ... синтаксической ошибке в строке (eval 1) 1, рядом с "."
Amber
8
Правильный синтаксис , rename -S .html .text *.htmlгде -Sрасшифровывается--subst-all
Марек Sebera
8
brew install rename
Ник
4
@GregHewgill переименование доступно для Mac OS с HomeBrew
CodeBrauer
15

Для пользователей Ubuntu:

rename 's/\.html$/\.txt/' *.html
Беру Лал Лохар
источник
Это не рекурсивно, но у меня это сработало в Ubuntu 14.04.
Макс Уоллес
9

Это самое приятное решение, которое я нашел, которое работает на OSX и Linux, и оно прекрасно работает и с git!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

и с мерзавцем:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

bdombro
источник
8

Вот пример команды переименования:

rename -n s/\.htm$/\.html/’ *.htm

Параметр -n означает, что это тестовый запуск, и он не изменит никаких файлов. Он покажет вам список файлов, которые будут переименованы, если вы удалите -n. В приведенном выше случае он преобразует все файлы в текущем каталоге из файла с расширением .htm в .html.

Если результат вышеприведенного тестового прогона выглядел нормально, вы можете запустить финальную версию:

rename -v s/\.htm$/\.html/’ *.htm

Параметр -v является необязательным, но рекомендуется включить его, поскольку он является единственной записью изменений, которые были внесены командой переименования, как показано в примере выходных данных ниже:

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

Сложная часть в середине - это подстановка Perl с регулярными выражениями, выделенными ниже:

rename -v s/\.htm$/\.html/’ *.htm
А.А.
источник
6

В этом вопросе явно упоминается Bash, но если у вас есть ZSH, это довольно просто:

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

Если вы получили, zsh: command not found: zmvто просто запустите:

autoload -U zmv

А потом попробуйте еще раз.

Спасибо этой оригинальной статье за совет о ZMV.

Майкл Леонард
источник
4

После сканирования чужого веб-сайта я обнаружил, что тысячи файлов не имеют расширения .html в широком дереве подкаталогов.

Чтобы переименовать их все за один раз, кроме файлов, уже имеющих расширение .html (у большинства из них их вообще не было), это сработало для меня:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

В случае с OP я мог бы немного изменить это, чтобы переименовывать только файлы * .txt, например так:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

Разбитый (время молотка!):

-iname * .txt
- означает, что ТОЛЬКО файлы, заканчивающиеся на .txt

mv -iv "{}. {txt, html}" - Когда find передает {} в качестве имени файла, $ {filename%. *} извлекает свое базовое имя без какого-либо расширения, чтобы сформировать параметры для mv . bash использует {txt, html}, чтобы переписать его как два параметра, поэтому последняя команда выполняется так:mv -iv "filename.txt" "filename.html"

Нужно исправить, хотя: работа с пробелами в именах файлов

Marcos
источник
4

Командаmmv , кажется, очень эффективно выполнить эту задачу на огромное количество файлов (десятки тысяч в секунду). Например, чтобы переименовать все .xmlфайлы в .htmlфайлы, используйте это:

mmv ";*.xml" "#1#2.html"

;будет соответствовать пути, то *будет совпадать с именем файла, и они упоминаются как #1и #2во имя замены.

Ответы на основе execили конвейеры были либо слишком медленными, либо терпели неудачу на очень большом количестве файлов.

Роко Мижич
источник
3

Попробуй это

rename .html .txt *.html 

Применение:

rename [find] [replace_with] [criteria]
П Шридхар
источник
3

Немного опоздал на вечеринку. Вы можете сделать это с помощью xargs:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

Или если все ваши файлы находятся в какой-то папке

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
особ
источник
3
Нет . Не разобратьls . Эта команда смешная: она бесполезно использует глоб ls, а не напрямую использует глоб. Это будет разрываться с именами файлов, содержащими пробелы, кавычки и (из-за отсутствия кавычек) символы глобуса.
gniourf_gniourf
К вашему сведению, ваша связанная статья содержит обновленную заметку, в которой говорится, что более новый LS «правильно« оболочка избегает »файлов при печати на терминале». Ваша точка зрения все еще остается хорошим эмпирическим правилом.
Katastic Voyage
3

Это хороший способ изменить несколько расширений одновременно:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

Примечание: будьте осторожны, чтобы размер расширения был одинаковым (???)

Ник Де Грек
источник
2

Красиво и просто!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Дино
источник
2

Если вы предпочитаете PERL, существует короткий сценарий PERL (первоначально написанный Ларри Уоллом, создателем PERL), который будет делать именно то, что вы хотите здесь: tips.webdesign10.com/files/rename.pl.txt .

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

rename.pl 's/html/txt/' *.html
dudusan
источник
2
На этот вопрос уже был дан ответ, и он уже давно принят, и не похоже, что ваш ответ принесет что-то большее, чем то, что уже было сказано.
ChristopheLec
1
+1, так как это был сценарий Ларри Уолла (модифицированный Робином Баркером). Последний доступный URL-адрес таков
loretoparisi
1

Подобно тому, что было предложено ранее, вот как я это сделал:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

Я сначала проверил с

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
Карл Бош
источник
1

Одна строка, без петель:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

Пример:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt
Кристиан Бонджорно
источник
+1 для показа способа только для bash, который не зависит от точного соответствия существующего расширения. Это работает для любого входного расширения, будь то 3 символа длиной или 4 символа или более
Ciprian Tomoiagă
0

К сожалению, это не тривиально, чтобы сделать портативно. Вам, вероятно, нужно немного опыта магии.

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

Уберите эхо, как только вы будете счастливы, он сделает то, что вы хотите.

Edit: basename вероятно, немного более читабелен для этого конкретного случая, хотя exprв целом он более гибкий.

CB Bailey
источник
Хотя это, возможно, не лучший ответ на вопрос, это было для меня! Мне нужен был способ переименовать только в строку весь путь, а не просто имя файла. Спасибо за публикацию!
пончик
0

Вот что я использовал для переименования .edgeфайлов в.blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

Работает как шарм.

Никсон Косгей
источник
0

Вы также можете создать функцию в Bash, добавить ее .bashrcили что-то еще, а затем использовать ее где угодно.

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

Применение:

change-ext css scss

Источник кода в функции: https://stackoverflow.com/a/1224786/6732111

J Kluseczka
источник
0

Переименуйте расширения файлов для всех файлов в текущем каталоге и подкаталогах без каких-либо других пакетов (используйте только сценарий оболочки):

  1. Создать сценарий оболочки rename.sh в текущем каталоге со следующим кодом:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Запустить его ./rename.sh .old .new .

    Например. ./rename.sh .html .txt

Нео Лю
источник