Como alterar a extensão de vários arquivos da linha de comando?

58

Tenho muitos arquivos com a extensão .abc e quero alterá-los para .edefg
Como fazer isso a partir da linha de comando?

EDITAR : Eu tenho uma pasta raiz com muitas subpastas, então a solução deve funcionar -r recursivamente.

    
por tommyk 19.04.2011 / 14:02

8 respostas

72

Uma maneira portátil (que funcionará em qualquer sistema compatível com POSIX):

find /the/path -depth -name "*.abc" -exec sh -c 'mv "" "${1%.abc}.edefg"' _ {} \;

No bash4, você pode usar globstar para obter globs recursivos (**):

shopt -s globstar
for file in /the/path/**/*.abc; do
  mv "$file" "${file%.abc}.edefg"
done

O comando (perl) rename no Ubuntu pode renomear arquivos usando a sintaxe de expressão regular perl, que você pode combinar com globstar ou find :

# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)  

# Best to process the files in chunks to avoid exceeding the maximum argument 
# length. 100 at a time is probably good enough. 
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
  rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done

# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +

Veja também o link

    
por geirha 19.04.2011 / 20:51
37

Isso fará a tarefa necessária se todos os arquivos estiverem na mesma pasta

rename 's/.abc$/.edefg/' *.abc

Para renomear os arquivos de forma recursiva, use isto:

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
    
por Chakra 19.04.2011 / 14:23
11

Um problema com renomeação recursiva é que qualquer que seja o método usado para localizar os arquivos, ele passa todo o caminho para rename , não apenas o nome do arquivo. Isso dificulta a criação de renomeações complexas em pastas aninhadas.

Eu uso a ação find -execdir para resolver esse problema. Se você usar -execdir em vez de -exec , o comando especificado será executado a partir do subdiretório que contém o arquivo correspondente. Portanto, em vez de passar todo o caminho para rename , ele passa apenas ./filename . Isso torna muito mais fácil escrever o regex.

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_.abc/' '{}' \;

Em detalhes:

  • -type f significa procurar apenas arquivos, não diretórios
  • -name '*.abc' significa significa apenas corresponder nomes de arquivos que terminam em .abc
  • As barras invertidas após -type e -name são o caractere de continuação da linha de bash. Eu os uso para tornar este exemplo mais legível, mas eles não são necessários na prática.
  • No entanto, a barra invertida no final da linha -execdir é necessária. Ele está lá para expor o ponto-e-vírgula, que finaliza o comando executado por -execdir . Diversão!

Explicação do regex:

  • s/ início da regex
  • \.\/ corresponde ao líder ./que o -execdir passa. Use \ para escapar do. e / metacaracteres
  • (.+) corresponde ao nome do arquivo. Os parênteses capturam a correspondência para uso posterior
  • \.abc escape do ponto, combine o abc
  • $ ancora a correspondência no final da string

  • / marca o final da parte "correspondência" da expressão regular e o início da parte "substituir"

  • version1_ adicione este texto a todos os nomes de arquivo

  • faz referência ao nome do arquivo existente, porque capturamos com parênteses. Se você usar vários conjuntos de parênteses na parte "match", você pode consultá-los aqui usando $ 2, $ 3, etc.
  • .abc o novo nome do arquivo terminará em .abc. Não há necessidade de escapar do metacaractere ponto aqui na seção "substituir"
  • / end do regex

Antes

tree --charset=ascii

|-- a_file.abc
|-- Another.abc
|-- Not_this.def
'-- dir1
    '-- nested_file.abc

Depois

tree --charset=ascii

|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
'-- dir1
    '-- version1_nested_file.abc

Dica: a opção rename 's -n é útil. Ele faz uma corrida a seco e mostra a você quais nomes ele mudará, mas não faz alterações.

    
por Christian Long 06.10.2012 / 00:48
5

Outra forma portátil:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "" "$(dirname "")/$(basename "" .abc).edefg"' _ '{}' \;
    
por aNeutrino 03.02.2013 / 17:36
0
# Rename all *.txt to *.text
for f in *.txt; do 
mv -- "$f" "${f%.txt}.text"
done

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

Editar: se você tiver que usar o basename, sua sintaxe seria:

for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done

link

    
por ashanrupasinghe 22.08.2016 / 14:12
0

Isso é o que eu fiz e trabalhei bem do jeito que eu queria. Eu usei o comando mv . Eu tinha vários arquivos .3gp e queria renomeá-los para .mp4

Aqui está um pequeno oneliner:

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

Que simplesmente varre o diretório atual, pega todos os arquivos .3gp e renomeia (usando o mv) em ren-name_of_file.mp4

    
por Rexford 13.03.2016 / 22:58
0

Encontrei uma maneira fácil de conseguir isso. Para alterar extensões de muitos arquivos de jpg para pdf, use:

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
    
por Peaceful 27.09.2017 / 05:39
0

Eu usaria o comando mmv do pacote do mesmo nome :

mmv ';*.abc' '#1#2.edefg'

O ; corresponde a zero ou mais */ e corresponde a #1 na substituição. O * corresponde a #2 . A versão não recursiva seria

mmv '*.abc' '#1.edefg'
    
por MvG 20.05.2018 / 23:13