Como renomeio a extensão para um lote de arquivos?

Em um diretório, eu tenho um monte de arquivos *.html .

Eu gostaria de renomeá-los todos para *.txt

Eu uso o shell bash.

Para uma solução melhor (com apenas funcionalidade bash, ao contrário de chamadas externas), consulte uma das outras respostas .


O seguinte faria e não exige que o sistema tenha o programa de rename (embora você tenha mais freqüentemente isso em um sistema):

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

EDIT: Como apontado nos comentários, isso não funciona para nomes de arquivos com espaços neles sem cotação adequada (agora adicionado acima). Ao trabalhar apenas com seus próprios arquivos que você sabe que não tem espaços nos nomes de arquivos, isso funcionará, mas sempre que você escrever algo que possa ser reutilizado mais tarde, não ignore as citações corretas.

Se estiver usando o bash, não há necessidade de comandos externos como sed, basename, rename, expr, etc.

 for file in *.html do mv "$file" "${file%.html}.txt" done 
 rename 's/\.html$/\.txt/' *.html 

faz exatamente o que você quer.

Você quer usar rename :

 rename -S .html .txt *.html 

Isso faz exatamente o que você quer – ele vai mudar a extensão de .html para .txt para todos os arquivos correspondentes a *.html .

Nota: Greg Hewgill corretamente aponta que isso não é um constructo básico; e é um comando separado do Linux. Se você só precisa de algo no Linux, isso deve funcionar bem; Se você precisar de algo mais multi-plataforma, então dê uma olhada em uma das outras respostas.

Isso funcionou para mim no OSX de .txt para .txt_bak

 find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \; 

Em um Mac …

  1. Instalar renomear se você não tiver: brew install rename
  2. rename -S .html .txt *.html

Para usuários do Ubuntu:

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

Aqui está um exemplo do comando renomear:

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

O -n significa que é um teste e não irá realmente alterar nenhum arquivo. Ele mostrará uma lista de arquivos que seriam renomeados se você removesse o -n. No caso acima, ele converterá todos os arquivos no diretório atual de uma extensão de arquivo de .htm para .html.

Se a saída do teste acima parecesse ok, você poderia executar a versão final:

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

O -v é opcional, mas é uma boa idéia incluí-lo, pois é o único registro que você terá das mudanças feitas pelo comando renomear, conforme mostrado na saída abaixo:

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

A parte complicada no meio é uma substituição Perl com expressões regulares, destacada abaixo:

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

Depois que alguém rastreou o site, acabei com milhares de arquivos sem a extensão .html, em uma ampla tree de subdiretórios.

Para renomeá-los todos de uma só vez, exceto os arquivos que já tinham uma extensão .html (a maioria deles não tinha nenhum), isso funcionou para mim:

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

No caso do OP, eu poderia modificar isso um pouco, apenas para renomear arquivos * .txt, assim:

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

Dividido (hammertime!):

-iname * .txt
– Significa considerar APENAS arquivos já terminados em .txt

mv -iv “{}. {txt, html}” – Quando find passa um {} como o nome do arquivo, $ {filename%. *} extrai seu nome de base sem qualquer extensão para formar os parâmetros para mv . O bash pega o {txt, html} para reescrevê-lo como dois parâmetros, então o comando final é executado como: mv -iv "filename.txt" "filename.html"

Correção necessária: lidar com espaços em nomes de arquivos

Tente isso

 rename .html .txt *.html 

uso:

 rename [find] [replace_with] [criteria] 

Um pouco atrasado para a festa. Você poderia fazer isso com xargs:

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

Ou se todos os seus arquivos estiverem em alguma pasta

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

Esta questão menciona explicitamente o Bash, mas se você tiver o ZSH disponível, é bem simples:

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

Se você obtiver o zsh: command not found: zmv então simplesmente execute:

 autoload -U zmv 

E então tente novamente.

Graças a este artigo original para a dica sobre o zmv.

O comando mmv parece fazer essa tarefa de maneira muito eficiente em um grande número de arquivos (dezenas de milhares em um segundo). Por exemplo, para renomear todos os arquivos .xml para arquivos .html , use o seguinte:

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

o ; irá corresponder ao caminho, o * irá corresponder ao nome do arquivo, e estes são referidos como #1 e #2 no nome de substituição.

As respostas baseadas em exec ou pipes foram muito lentas ou falharam em um grande número de arquivos.

Se você preferir PERL, existe um pequeno script PERL (orignally escrito por Larry Wall, o criador do PERL) que fará exatamente o que você deseja aqui: tips.webdesign10.com/files/rename.pl.txt . Por exemplo, o seguinte deve fazer o truque

rename.pl 's/html/txt/' *.html

=)

(Obrigado @loretoparisi pela URL atualizada)

Infelizmente não é trivial fazer portável. Você provavelmente precisa de um pouco de magia expr.

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

Remova o eco assim que estiver satisfeito e faça o que quiser.

Edit: basename é provavelmente um pouco mais legível para este caso em particular, embora expr seja mais flexível em geral.

Aqui está o que eu usei para renomear arquivos .blade.php para .blade.php

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

Funciona como charme.