Como renomeio a extensão para vários arquivos?


480

Em um diretório, tenho vários *.htmlarquivos. Eu gostaria de renomear todos eles para*.txt

Como eu posso fazer isso? Eu uso o shell bash.

Respostas:


382

Para uma solução melhor (apenas com funcionalidade bash, em oposição a chamadas externas), consulte uma das outras respostas .


O seguinte requer e não exige que o sistema possua o renameprograma (embora você o possua com mais freqüência 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 uma citação adequada (agora adicionada acima). Ao trabalhar exclusivamente em seus próprios arquivos que você sabe que não têm espaços nos nomes dos arquivos, isso funcionará, mas sempre que você escrever algo que possa ser reutilizado posteriormente, não pule a citação adequada.


47
Uma alternativa, sem basename e com citações: mv "$ {file}" "$ {file /% html / .txt.}" (Ver man bash, Parâmetro de Expansão para mais detalhes)
Rodrigo Queiró

7
Só é bom se os arquivos estiverem todos no diretório atual, é claro, porque o nome da base retira a parte do nome do caminho. Apenas um 'cuidado'!
31440 Jonathan Leffler

6
Essa solução é ruim, não apenas porque é lenta, mas porque não funciona com nomes de arquivos com espaços neles. Você deve SEMPRE fazer uma cotação adequada em scripts bash. mv "$ file" "$ (nome básico" $ file ".html)". txt seria muito melhor. Mas ainda assim, o mv "$ files" "$ {files% .html} .txt" é muito melhor.
Balázs Pozsár 4/08/09

8
nas janelas que você acabou de fazerren *.a *.b
Muhammad Umer

2
No mínimo, use a $()sintaxe especificada pelo POSIX em vez da sintaxe do backtick herdado. Melhora a legibilidade e torna a sintaxe muito menos ambígua quando você tem caracteres que precisariam ser escapados por barra invertida para serem literais dentro da substituição de comando pelo último.
Charles Duffy

669

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

12
E se você não souber a extensão do arquivo, poderá usá-la "${file%.*}.txt", mas isso pode ser perigoso para arquivos sem uma extensão.
Jess

1
Note para qualquer um que tenha problemas para fazer isso funcionar como eu: note que não há $dentro do aparelho!
Doug65536

5
Eu preciso de uma maneira de permanentemente favorito / Bookmark esta resposta, eu nunca lembro a sintaxe exata e eu acabo pesquisando para ele
boliva

7
@danip A construção de porcentagem de sinal dentro do colchete retira os caracteres do final. Há também uma construção de hash-dentro-colchete que retira caracteres do início. Confira: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2

4
Outra resposta de troca de pilha (que não consigo encontrar!) Sugeriu isso, mas também usando o --"operator": mv - "$ file" "$ {file% .html} .txt" Esse operador evita nomes de arquivos que começam com um '-' de ser analisado por mv como argumentos.
precisa saber é o seguinte

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

faz exatamente o que você quer.


Eu não acho que você pode usar um regex literal no bash como você sugere - qual shell você está usando?
Daver

1
eu estou usando um terminal Mac
bmw0128

Aqui está a página de manual para a versão de renomeação no Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Âmbar

renomear é um comando em alguns sistemas. Eu tenho um script Perl (originalmente do primeiro livro do Camel) que faz o trabalho. Há também um programa GNU com o mesmo nome que faz aproximadamente o mesmo trabalho. Meu Mac não possui um comando 'renomear' fornecido pelo sistema - ou não está no meu PATH (que é moderadamente abrangente).
23416 Jonathan Leffler

Há uma fórmula de renomeação no Homebrew.
Revprez

112

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

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

4
Funciona bem no linux também.
Diziet 30/03

É além do ponto, mas para ir de .txtque .txt_bakvocê só tem que concatenar _bak;)
corwin.amber

3
Isso é bom para renomear recursivamente
leachryanb

Ótimo! (sob Ubuntu 16.04) Meu caso de uso prático, renomeando tudo .scsspara .sass(após a conversão no local…):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke

2
este trabalhou com +6000 arquivos, renomear relatou "lista de argumentos foi muito longa"
Tony Cronin

94

Você quer usar rename:

rename -S .html .txt *.html

Isso faz exatamente o que você deseja - alterará a extensão de .htmlpara .txtpara todos os arquivos correspondentes *.html.

Nota: Greg Hewgill indica corretamente que este não é um bash embutido; e é um comando Linux separado. Se você só precisa de algo no Linux, isso deve funcionar bem; se você precisar de algo mais entre plataformas, dê uma olhada em uma das outras respostas.


7
Embora essa seja uma boa solução, o rename programa não está relacionado bashe também não está disponível em todas as plataformas. Eu só vi isso no Linux.
Greg Hewgill 03/08/09

15
"$ renomear .html .txt * .html" resulta em ... erro de sintaxe na (eval 1) linha 1, próxima a "."
Âmbar

8
Sintaxe correta é o lugar rename -S .html .text *.htmlonde -Ssignifica--subst-all
Marek Sebera

8
renomear instalação de cerveja
Nick

4
A renomeação de @GregHewgill está disponível para Mac OS com HomeBrew
CodeBrauer

36

Em um Mac ...

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


9

Esta é a solução mais eficiente que encontrei que funciona no OSX e Linux e também funciona bem com o git!

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

e com git:

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


8

Aqui está um exemplo do comando renomear:

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

O -n significa que é uma execução de teste e, na verdade, não altera 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 .htm para .html.

Se a saída da execução de teste acima parecer boa, você poderá 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 alterações que foram feitas pelo comando rename, conforme mostrado na amostra de 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 do meio é uma substituição de Perl com expressões regulares, destacada abaixo:

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

6

Esta pergunta menciona explicitamente o Bash, mas se você tiver o ZSH disponível, é bastante simples:

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

Se você conseguir zsh: command not found: zmv, basta executar:

autoload -U zmv

E então tente novamente.

Obrigado a este artigo original pela dica sobre o zmv.


4

Após o rastreamento do site de outra pessoa, acabei com milhares de arquivos ausentes na extensão .html, em uma grande árvore de subdiretórios.

Para renomear todos eles de uma só vez, exceto os arquivos que já possuem uma extensão .html (a maioria deles não tinha nenhuma), 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 posso modificar isso um pouco, para renomear apenas arquivos * .txt, da seguinte maneira:

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

Quebrado (hora do martelo!):

-iname * .txt
- significa considerar SOMENTE arquivos que já terminam em .txt

mv -iv "{}. {txt, html}" - Quando find passa a {} como o nome do arquivo, $ {filename%. *} extrai seu nome de base sem nenhuma extensão para formar os parâmetros para mv . o bash usa o {txt, html} para reescrevê-lo como dois parâmetros, para que o comando final seja executado como:mv -iv "filename.txt" "filename.html"

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


4

O comandommv parece executar essa tarefa com muita eficiência em um grande número de arquivos (dezenas de milhares em um segundo). Por exemplo, para renomear todos os .xmlarquivos para .htmlarquivos, use este:

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

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

As respostas baseadas em execou pipes foram muito lentas ou com falha em um número muito grande de arquivos.


3

Tente isto

rename .html .txt *.html 

uso:

rename [find] [replace_with] [criteria]

3

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' - {}

3
Nãols . Não analise . Esse comando é ridículo: ele usa um glob inutilmente ls, em vez de usar diretamente o glob. Isso quebrará os nomes de arquivos que contêm espaços, aspas e (devido à falta de aspas) caracteres glob.
gniourf_gniourf

Para sua informação, seu artigo vinculado contém uma observação atualizada que diz que LS mais recente "corretamente" shell escapa "arquivos se impressos no terminal". Seu argumento ainda é uma boa regra de ouro.
Katastic Voyage 27/03

3

Esta é uma boa maneira de modificar várias extensões ao mesmo tempo:

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

Nota: tenha cuidado com o tamanho da extensão para ser o mesmo (o ???)


2

Agradável e simples!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;

2

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

Para o seu exemplo, o seguinte deve fazer o truque:

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

2
Esta pergunta já foi respondida e aceita há muito tempo e parece que sua resposta não traz nada além do que já foi dito.
ChristopheLec

1
+1, pois era um script de Larry Wall (modificado por Robin Barker). O último URL disponível é este: tips.webdesign10.com/files/rename.pl.txt
loretoparisi

1

Similar ao que foi sugerido antes, foi assim que eu fiz:

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

Eu primeiro validei com

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

1

Uma linha, sem loops:

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

Exemplo:

$ 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 por mostrar uma maneira somente bash que não depende exatamente da extensão existente. Isso funciona para qualquer extensão de entrada, seja com 3 caracteres ou 4 caracteres ou mais
Ciprian Tomoiagă

0

Infelizmente, não é trivial fazer portably. 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 quando estiver feliz, pois ele faz o que deseja.

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


Embora essa possa não ser a melhor resposta para a pergunta, foi para mim! Eu precisava de uma maneira de renomear apenas na string um caminho inteiro, não apenas o nome do arquivo. Obrigado por publicar!
rosquinha

0

Aqui está o que eu costumava renomear .edgearquivos para.blade.php

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

Funciona como charme.


0

Você também pode criar uma função no Bash, adicioná-la .bashrcou algo assim e usá-la onde quiser.

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

Uso:

change-ext css scss

Origem do código na função: https://stackoverflow.com/a/1224786/6732111


0

Renomeie as extensões de arquivo para todos os arquivos no diretório e subdiretórios atuais sem outros pacotes (use apenas o shell script):

  1. Crie um script de shell rename.shno diretório atual com o seguinte código:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Corra ./rename.sh .old .new.

    Por exemplo. ./rename.sh .html .txt

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.