Renomeia arquivos recursivamente - oneliner de preferência [duplicado]

6

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

    
por zetah 18.11.2011 / 13:24

4 respostas

6

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.

    
por ams 18.11.2011 / 13:45
3

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.

    
por xubuntix 18.11.2011 / 14:07
1

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
  • Nessa resposta, estou usando o comando rename em vez de mv. renomear usa uma expressão regular Perl para renomear cada arquivo.
  • 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 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.

    
por Christian Long 06.10.2012 / 03:32
0

Você pode explorar a infinidade de opções disponíveis:

'$ apt-cache search rename | grep -i rename' 
    
por waltinator 18.11.2011 / 22:18

Tags