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
endólito
fonte
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

endólito
fonte
14

Algo como:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
cYrus
fonte
este funcionou melhor para mim
cwd
14

Com zsh:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Remova o -npara realmente executar a renomeação.

Gilles 'SO- parar de ser mau'
fonte
11
Resposta fantástica!
precisa saber é o seguinte
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.

Bernd Wechner
fonte
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.

Ciro Santilli adicionou uma nova foto
fonte