Respostas:
Uma maneira portátil (que funcionará em qualquer sistema compatível com POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
No bash4, você pode usar a globstar para obter globs recursivos (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
O renamecomando (perl) no Ubuntu pode renomear arquivos usando a sintaxe de expressão regular perl, que você pode combinar com a 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 http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c o primeiro argumento é atribuído a $ 0 e os argumentos restantes são atribuídos aos parâmetros posicionais . Portanto, _é um argumento fictício e '{}' é o primeiro argumento posicional a sh -c.
Isso fará a tarefa necessária se todos os arquivos estiverem na mesma pasta
rename 's/.abc$/.edefg/' *.abc
Para renomear os arquivos recursivamente, use isto:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcem uma versão moderna do Bash.
sno começo, e que outras opções posso usar lá. Obrigado !
Um problema com as renomeações recursivas é que, independentemente do método usado para localizar os arquivos, ele passa o caminho inteiro para rename, não apenas o nome do arquivo. Isso dificulta a renomeação complexa em pastas aninhadas.
Eu uso finda -execdiração de para resolver este problema. Se você usar em -execdirvez de -exec, o comando especificado será executado no subdiretório que contém o arquivo correspondente. Então, ao invés de passar o caminho inteiro rename, ele apenas passa ./filename. Isso facilita muito escrever o regex.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
Em detalhe:
-type f significa apenas procurar arquivos, não diretórios-name '*.abc' significa apenas nomes de arquivos de correspondência que terminam em .abc'{}'é o espaço reservado que marca o local em -execdirque o caminho encontrado será inserido. As aspas simples são necessárias, para permitir que ele lide com nomes de arquivos com espaços e caracteres de shell.-typee -namesão o caractere de continuação de linha bash. Eu os uso para tornar este exemplo mais legível, mas eles não são necessários se você colocar seu comando em uma única linha.-execdirlinha é necessária. Ele existe para escapar do ponto-e-vírgula, que encerra o comando executado por -execdir. Diversão!Explicação do regex:
s/ início da regex\.\/coincidir com o ./ principal que o -execdir passa. Use \ para escapar do. e / metacaracteres (nota: esta parte varia dependendo da sua versão do find. Veja o comentário do usuário @apollo)(.+)corresponde ao nome do arquivo. Os parênteses capturam a correspondência para uso posterior\.abc escape do ponto, combine o abc$ ancorar a partida no final da string
/ marca o final da parte "correspondente" da regex e o início da parte "substituir"
version1_ adicione este texto a cada nome de arquivo
$1referencia o nome do arquivo existente, porque o capturamos entre parênteses. Se você usar vários conjuntos de parênteses na parte "correspondente", poderá consultá-los aqui usando $ 2, $ 3 etc..abco novo nome do arquivo terminará em .abc. Não há necessidade de escapar do metacaractere de ponto aqui na seção "substituir"/ fim da regexAntes
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Depois de
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Dica: renamea opção -n é útil. Ele executa uma execução a seco e mostra quais nomes serão alterados, mas não faz nenhuma alteração.
--execdirnão passou na liderança, ./portanto a \.\/parte no regex pode ser omitida. Pode ser que eu esteja no OSX e não no ubuntu
Outra maneira portátil:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# 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ê precisar usar o nome da base, sua sintaxe será:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
Isto é o que eu fiz e funcionou da maneira que eu queria. Eu usei o mvcomando. Eu tinha vários .3gparquivos e queria renomeá-los todos para.mp4
Aqui está um breve guia para ele:
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) para ren-name_of_file.mp4
file.3gppara file.3gp.mp4, o que pode não ser o que a maioria das pessoas deseja.
.3gpou .mp4aqui foram apenas para fins ilustrativos.
basename "$i" .mp4para remover a extensão anterior em vez de "ren- $ i.mp4".
Eu usaria o comando mmv do pacote com o mesmo nome :
mmv ';*.abc' '#1#2.edefg'
Os ;corresponde a zero ou mais */e corresponde #1na substituição. O *corresponde a #2. A versão não recursiva seria
mmv '*.abc' '#1.edefg'
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: Por que o uso da ação '-execdir' é inseguro para o diretório que está no PATH?
-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: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
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.