find . -name '*.txt' -print0 | xargs -0 -n1 bash -c 'mv "$0" "${0/oldname/newname}"'
Obviamente, esse padrão de renomeação é apenas um exemplo simples, mas cuidado, pois ele edita o caminho inteiro, não apenas o nome do arquivo.
Eu encontrei esta resposta como faço para ... mas simplesmente não funciona - ele não renomeou nenhum arquivo por razões desconhecidas para mim
Antes de começar a pesquisar, achei que deveria ser uma tarefa fácil, mesmo para o pinguim novato, mas não parece ser assim para mim.
Por exemplo, eu simplesmente não posso dizer a ls para listar todos os *.txt em todas as subpastas, o que foi uma surpresa para mim (sem grep ou similar).
Então eu achei find e find . -name name_1.txt listas arquivos bem, mas
for f in $(find . -name name_1.txt) ; do echo "$f" ; done
divide caminhos de arquivos inteiros com espaço como separador, portanto, é inutilizável passar essa saída para algum comando como mv ou rename
Eu quero perguntar o que há de errado com o comando acima e, se possível, algum oneliner bacana, para que eu possa renomear recursivamente name_1.txt to name_2.txt
find . -name '*.txt' -print0 | xargs -0 -n1 bash -c 'mv "$0" "${0/oldname/newname}"'
Obviamente, esse padrão de renomeação é apenas um exemplo simples, mas cuidado, pois ele edita o caminho inteiro, não apenas o nome do arquivo.
o comando mmv fará isso em uma chamada bem simples:
mmv "; name_1.txt" "# 1name_2.txt"
O ";" O caractere curinga, que é reutilizado no nome do arquivo de substituição como "# 1", também corresponde a subdiretórios.
Se precisar de exemplos mais complicados, você deve procurar na página do manual.
Como apontam @ams, muitas soluções recursivas de substituição exigem que você trabalhe com todo o caminho, não apenas com o nome do arquivo.
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 comando replace.
find /the/path -type f \
-name '*_one.txt' \
-execdir rename 's/\.\/(.+)_one\.txt$/$1_two.txt/' {} \;
Em detalhes:
-type f significa procurar apenas arquivos, não diretórios -name '*_one.txt' significa significa apenas corresponder nomes de arquivos que terminam em _one.txt rename em vez de mv. renomear usa uma expressão regular Perl para renomear cada arquivo. -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. -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 início do nome do arquivo. Os parênteses capturam a correspondência para uso posterior _one\.txt match "_one.txt", escape do metacaractere de ponto $ 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" $1 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. _two.txt o novo nome do arquivo terminará em "_two.txt". Não há necessidade de escapar do metacaractere ponto aqui na seção "substituir" / end do regex Antes
tree --charset=ascii
|-- a_one.txt
|-- b_one.txt
|-- Not_this.txt
'-- dir1
'-- c_one.txt
Depois
tree --charset=ascii
|-- a_two.txt
|-- b_two.txt
|-- Not_this.txt
'-- dir1
'-- c_two.txt
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.
Você pode explorar a infinidade de opções disponíveis:
'$ apt-cache search rename | grep -i rename'
Tags bash