cleaner script para substituir recursivamente uma string em todos os diretórios e nomes de arquivos [duplicados]

1

Eu quero substituir uma string por uma string diferente em todos os diretórios e nomes de arquivos, recursivamente. Então, se eu quiser substituir foo com bar e ter esse arquivo:

 foo_project/my_app/old_foo/start_foo.sh

Eu gostaria que ele se tornasse

 bar_project/my_app/old_bar/start_bar.sh

Eu consegui fazer isso, mas é bem feio. Escrevê-lo da memória (não é possível copiar colar para perdoar erros de digitação) o comando que eu tenho é:

find $PROJECT_DIR -name "*foo*" | tac | xargs -n 1 -I % bash -c "eval mv % \$\( echo % \| sed \''s/\(.*\)foo/$PROJECT_NAME/'\' \)"

Isso funciona para mim, mas é horrível. Existe uma abordagem mais limpa para fazer o que eu quero?

Para contextualizar o comando acima, o problema que tive foi que os primeiros comandos de renomeação quebrariam os comandos mv posteriores, tornando os caminhos diferentes. É por isso que eu mudei para um tac antes de um xargs (em vez do argumento -evalcmd para localizar com o qual comecei) para garantir que executei primeiro os renomeados mais profundamente aninhados. Eu então tive que fazer meu sed apenas renomear a última instância do foo para que eu pudesse mover tudo dentro de uma pasta antes de renomear a pasta.

A parte feia é a necessidade de eval e, portanto, vários níveis de argumentos de escape, porque de outra forma eu não sabia como passar o conteúdo de xargs para o comando sed. Tem que haver algo mais limpo, então isso embora?

    
por dsollen 25.07.2016 / 20:04

2 respostas

0

Para coisas potencialmente complicadas e potencialmente perigosas como essa, eu gosto de gerar um script para fazer o que eu quero.

$ find foo_project -print > /tmp/list
$ vi /tmp/list
:%s/.*/'&'/            # quote all filenames just to be safe
:%s/.*/mv & &/         # generate mv commands
:%s/' '/'\r'/          # break them for the next step
:v/^mv /s/foo/bar/g    # modify the second arguments
:g/^mv /j              # re-join the lines

Agora, analise o script que você acabou de criar para ter certeza de que ele fará o que deseja:

mv 'foo_project/my_app/old_foo/start_foo.sh' 'bar_project/my_app/old_bar/start_bar.sh'
...

Se você gosta:

:wq
$ sh /tmp/list

Esta é uma técnica geral que uso o tempo todo. A maneira exata de editar o script depende do que você deseja realizar. Não é uma frase sexy, mas é seguro.

Agora, se isso é algo que você deseja fazer regularmente, e não uma única vez, essa técnica provavelmente não é o que você deseja. Mas para uma operação one-shot onde você está meio que se sentindo bem, isso funciona muito bem.

Agora, se você quiser uma solução reutilizável, é hora de escrever um script:

#!/bin/sh
find foo_project -print | while read filename; do
  newname='echo $filename | sed -e 's/foo/bar/g''
  echo "renaming $filename => $newname"
  mv "$filename" "$newname"
done
    
por 25.07.2016 / 22:47
1

Se você estiver usando o CentOS ou algum sistema sem rename (às vezes conhecido como prename ), então sugerido duplicado é um bom lugar para procurar. Se você está em um sistema derivado do Debian, isso pode funcionar para você também:

find "$PROJECT_DIR" -depth -type d -execdir echo rename 's/foo/bar/' {} +

Isso desce a árvore de diretórios profundidade primeiro e renomeia todos os itens em cada diretório, alterando foo para bar em cada instância.

(Na verdade, ele não faz nada, exceto mostrar o que ele faria. Remova echo quando estiver feliz ...)

    
por 25.07.2016 / 22:18

Tags