Como altero a extensão de vários arquivos?

168

Gostaria de alterar uma extensão de arquivo de *.txtpara *.text. Tentei usar o basenamecomando, mas estou tendo problemas para alterar mais de um arquivo.

Aqui está o meu código:

files=`ls -1 *.txt`

for x in $files
do
    mv $x "`basename $files .txt`.text"
done

Estou recebendo este erro:

basename: too many arguments Try basename --help' for more information
afbr1201
fonte
Algumas idéias em peteryu.ca/tutorials/shellscripting/batch_rename também
Nemo

Respostas:

176

Diretamente da Wiki de Greg :

# Renomeie todos * .txt para * .text
para f em * .txt; Faz
    mv - "$ f" "$ {f% .txt} .text"
feito

Veja também a entrada sobre por que você não deve analisarls .

Edit: se você tiver que usar basenamesua sintaxe seria:

para f em * .txt; Faz
    mv - "$ f" "$ (nome da base -" $ f ".txt) .text"
feito
jasonwryan
fonte
48
Há alguma sintaxe do Bash um pouco avançada usada aqui sem explicação. Eu tive que procurar muitas coisas no Google para entender isso completamente. Para ajudar outras pessoas na minha posição, aqui estão algumas referências sobre globs (a *.txtsintaxe) , o traço duplo simples-- e o uso do símbolo% na ${}construção . Até agora, eu nunca tinha encontrado os dois últimos e não sabia o que realmente estava acontecendo com o primeiro.
Mark Amery
3
Veja a resposta de Matthias Braun abaixo - muito mais simples, realiza a mesma coisa.
btk
10
Um linerfor f in *.txt; do mv -- "$f" "${f%.txt}.text"; done
Marçal Juan
11
Você está desaparecido; depois do texto ".
Pétur Ingi Egilsson 28/01
2
@ PéturIngiEgilsson na segunda linha? Não, não é necessário.
precisa saber é o seguinte
132

Aqui está como eu mudo todas as extensões de arquivo no diretório atual do Debian.

rename "s/oldExtension/newExtension/" *.txt

(Este é o Perl renamecomando, e não a util-linuxum. Veja Por que é o utilitário de renomeação no Debian / Ubuntu diferente do que em outras distribuições, como o CentOS? )

Matthias Braun
fonte
10
Muito mais simples que a resposta aceita, obrigado!
btk
8
No Mac, eu consegui brew install renamee isso funcionou.
Monkpit
3
com shell peixes que você pode fazer rename "s/oldExtension/newExtension/" **.txtpara mudar o nome all * .txt recursivamente
Palmstrom
3
Isso irá falhar footxt.txt. Em vez disso, use isto: unix.stackexchange.com/questions/19654/…
wisbucky 1/17/17
7
Quando os arquivos não tem qualquer extensão e pretende adicionar um:rename 's/$/.txt/' *
mkataja
35

Um comando simples, o renamefromutil-linux , fará isso por você, substituindo todas as ocorrências de "txt" por "text" em todos os arquivos correspondentes a "* .txt":

rename txt text *.txt
lamwaiman1988
fonte
4
renamealtera a primeira ocorrência, é melhor fazer isso rename .txt .text, mas isso nem sempre funciona (por exemplo, renomeia foo.txtx.bar.txtpara foo.textx.bar.txt).
Gilles
12
Note-se que nem todos os sistemas têm a mesma versão de renomeação; no Debian e nos amigos, o renamecomando é realmente perl-renamee usa expressões regulares perl. Para isso, o comando equivalente seria: rename 's/.txt/.text/' *.txt. As pessoas devem verificar o man renamesistema para descobrir qual delas possuem.
evilsoup
@evilsoup Esse é o caso para OSX, thx
Davi Lima
Isso também funciona em Cygwin (Windows)
andy
27
rename "s/oldExtension/newExtension/" *.txt

Acima funciona bem, mas limitado ao diretório atual. Experimente o comando abaixo, que é flexível com subdiretórios. Ele renomeará todos os .txtarquivos na estrutura de diretórios com uma nova extensão.

find . -name "*.txt" -exec rename 's/.txt$/.newext/' {} \;
Rahul
fonte
2
renamepode lidar com vários arquivos como argumento, você pode vastamente acelerar as coisas, usando +, em vez de \;se há muitos desses arquivos
Anthon
Ainda assim, é uma opção útil, pois "* .txt" pode ser aberto em uma grande lista de argumentos não suportada pelo shell.
Roman Shapovalov
11
"falhará em s / oldExtension / newExtension /" footxt.txt. Em vez disso, use isto: unix.stackexchange.com/questions/19654/…
wisbucky 1/17/17
9
for f in *.txt
do
    [ -f "$f" ] && mv "$f" "${f%txt}text"
done
Prince John Wesley
fonte
9

As respostas aqui referenciadas s/oldExtension/newExtension/estão erradas. Se você usar s/txt/text/, você converterá footxt.txtpara footext.txt, que não é o que você deseja. Mesmo se você usar s/.txt/.text/, isso seria convertido footxt.txtpara fo.text.txt.

Você precisa usar \.para corresponder ao período ( .corresponderá a qualquer caractere). E o final $para coincidir com o final da linha. Somente isso corresponderá corretamente à extensão.

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

rename 's/\.old$/.new/' *.old
wisbucky
fonte
7

Com base na resposta do @Prince John Wesley, aqui está um script simples para alterar todas as extensões de arquivos no diretório atual de ext1para ext2. Também gera nomes dos arquivos que estão sendo renomeados.

#!/bin/bash
for f in *.$1
do
    [ -f "$f" ] && mv -v "$f" "${f%$1}$2"
done

Exemplo de uso (assumindo que o nome do script seja change-ext):

change-ext ext1 ext2
Dennis Golomazov
fonte
Para alterar as extensões de arquivos nos diretórios recursivamente, substitua a segunda linha ( for...) por duas linhas: shopt -s globstare for f in **/*.$1. Requer Bash 4+.
Dennis Golomazov 02/02/2012
4

Razão # 53 para mudar para zsh:

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

Benitok
fonte
3

digamos que seus arquivos estão espalhados em vários diretórios. Supondo que dirx seja seu diretório pai, isso pode ser feito usando find:

for f in `find /dirx -iname '*.txt' -type f -print`;do  mv "$f" ${f%.txt}.text; done
Arash
fonte
E sobre tcsh ..
Josef Klimuk
2

Isto é o que funciona para mim:

find . -name '*.txt' -exec rename 's/\.txt$/.text/' \{} \;
yegor256
fonte
11
POR FAVOR, adicione um. antes do "texto"
danielmhanover
2

Quando você

não tem uma extensão para os arquivos de origem

e a extensão de destino é .text, você faria dessa maneira -

for f in *; do mv -- "$f" "${f%.\*}.text"; done
nitinr708
fonte
11
Excelente script bash-nativo. funcionou muito bem! for f in *.html; do mv -- "$f" "${f%.\*}.pug"; done
TamusJRoyce 19/07
1

Caso você queira saber o que deu errado na sua versão: Você usou no $fileslugar do $xcomando basename. Portanto, isso deve funcionar (não testado, no entanto):

for x in *.txt
do
  mv "$x" "`basename '$x' .txt`.text"
done
daniel kullmann
fonte