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.

bmw0128
fonte

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.

Mikael Auno
fonte
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
ghostdog74
fonte
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.

Âmbar
fonte
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"' {} \;
Steven Lizarazo
fonte
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.

DaveR
fonte
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
izilotti
fonte
15

Para usuários do Ubuntu:

rename 's/\.html$/\.txt/' *.html
Bheru Lal Lohar
fonte
Isso não é recursivo, mas funcionou para mim no Ubuntu 14.04.
Max Wallace
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' - '{}' \;

bdombro
fonte
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
AA
fonte
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.

Michael Leonard
fonte
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

Marcos
fonte
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.

Roko Mijic
fonte
3

Tente isto

rename .html .txt *.html 

uso:

rename [find] [replace_with] [criteria]
P Sreedhar
fonte
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' - {}
esp
fonte
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 ???)

Nick De Greek
fonte
2

Agradável e simples!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Deano
fonte
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
dudusan
fonte
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}"' {} \;
Carl Bosch
fonte
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
Christian Bongiorno
fonte
+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.

CB Bailey
fonte
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.

Nixon Kosgei
fonte
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

J Kluseczka
fonte
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

Neo Liu
fonte