Renomear arquivos recursivamente (alterar extensão) no Linux


22

Como renomear todos os arquivos em um diretório, recursivamente, alterando uma extensão para outra, para milhares de arquivos em milhares de subpastas? Eu vejo muitos comandos que fazem quase o que eu quero, mas não exatamente.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile

11
Você tem Debian renameou Red Hat rename?
Ignacio Vazquez-Abrams

@Ignacio: Ubuntu = Debian?
Endolith

Sim, o Ubuntu é um derivado do Debian.
Ignacio Vazquez-Abrams

Respostas:


23

Descobri isso

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

é claro, remova o -v quando estiver fazendo isso ou perderá tempo exibindo todos os arquivos


14

Algo como:

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

este funcionou melhor para mim
cwd


4

Eu achei esse método mais fácil e mais fácil de ler:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

Pelo menos nas derivações do Ubuntu, renomear leva uma lista de arquivos do STDIN se nenhum estiver na linha de comando. E isso pode ser testado facilmente com:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

até você acertar.


1

Renomeie arquivos e diretórios com find -execdir | rename

Se você vai renomear arquivos e diretórios, não apenas com um sufixo, esse é um bom padrão:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

A -execdiropção impressionante faz um cdno diretório antes de executar o renamecomando, ao contrário -exec.

-depth verifique se a renomeação ocorre primeiro nos filhos e, depois, nos pais, para evitar possíveis problemas com os diretórios-pai ausentes.

-execdir é necessário porque a renomeação não funciona bem com caminhos de entrada sem nome de base, por exemplo, o seguinte falha:

rename 's/findme/replaceme/g' acc/acc

A PATHinvasão é necessária porque -execdirtem uma desvantagem muito irritante: findé extremamente opinativa e se recusa a fazer qualquer coisa -execdirse você tiver algum caminho relativo em sua PATHvariável de ambiente, por exemplo ./node_modules/.bin, falhando com:

find: O caminho relativo './node_modules/.bin' está incluído na variável de ambiente PATH, que é insegura em combinação com a ação -execdir de find. Remova essa entrada de $ PATH

Consulte também: /ubuntu/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdiré uma extensão de localização GNU para POSIX . renameé baseado em Perl e vem do renamepacote. Testado no Ubuntu 18.10.

Mudar o nome da solução alternativa à procura

Se seus caminhos de entrada não vierem find, ou se você já teve o suficiente do aborrecimento do caminho relativo, podemos usar alguns Perl lookahead para renomear com segurança diretórios como em:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Eu não encontrei um análogo conveniente para -execdircom xargs: xargs: mudança de diretório de trabalho para o caminho do arquivo antes de executar?

O sort -ré necessário para garantir que os arquivos vir após seus respectivos diretórios, desde caminhos mais longos vir após mais curtos com o mesmo prefixo.

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.