Como obtenho esse comando find e rename para trabalhar com subdiretórios? [duplicado]

3

Eu tenho um grande diretório de arquivos de música que está mudando frequentemente conforme os arquivos e diretórios vêm e vão. Minha preferência é garantir que os nomes de arquivos e diretórios não possuam espaços, portanto, substituo todos eles por sublinhados.

Eu entro no diretório principal e executo este comando:

$ find -type d -exec rename 'y/\ /\_/' {} \;

O problema é que quando há subdiretórios, este comando parece se perder e retornará erros. Então, se eu tenho a seguinte estrutura de diretório:

...eseeuexecutarocomando,receboosseguinteserros:

$find-typed-execrename'y/\/\_/'{}\;find:'./Test02':Nosuchfileordirectoryfind:'./Test01':Nosuchfileordirectoryfind:'./Test03':Nosuchfileordirectory

Eoresultadoéqueminhaestruturadediretóriosseparececomisso.Observequeossubdiretóriosaindatêmespaços:

Se eu executar o comando novamente, obtenho esses erros, mesmo que pareça que ele renomeou os diretórios em questão:

$ find -type d -exec rename 'y/\ /\_/' {} \;
find: './Test_01/Test A': No such file or directory
find: './Test_01/Test C': No such file or directory
find: './Test_01/Test B': No such file or directory

Finalmente, eu corro o comando mais uma vez, e não recebo erros, e tenho todos os diretórios e subdiretórios nomeados da maneira que eu quero:

Obviamente, isso requer executar o comando mais vezes quando eu tiver vários subdiretórios, o que pode ser entediante.

Como posso fazer com que esse comando só precise ser executado uma vez e renomear todos os diretórios e subdiretórios de uma só vez?

Meu objetivo final é incluir isso em um script Bash para que eu possa executá-lo junto com outros comandos de manutenção similares, então eu preciso dele para não retornar erros ou precisar de mais informações minhas. Além disso, estou executando o Ubuntu 12.04 se isso faz diferença.

    
por Questioner 26.08.2012 / 05:02

1 resposta

3

Veja o que acontece:

  • find encontra o diretório correspondente ./Test 02 .
  • find executa o comando rename nesse diretório.
  • rename renames Test 02 para Test_02 .
  • find tenta descer no diretório Test 02 . Mas isso não existe mais.

A maneira mais fácil de resolver esse problema é dizer ao find para trabalhar ao contrário: primeiro procure por correspondências dentro do diretório e, em seguida, verifique se o diretório em si corresponde. Isso é o que a opção -depth faz.

Se você adicionar apenas -depth , encontrará outro problema, que quando find atingir Test 01/Test A , invocará rename 'y/\ /\_/' 'Test 01/Test A' , que tentará renomear esse diretório para Test_01/Test_A . Isso falhará, pois não há diretório chamado Test_01 . Uma solução fácil é usar a opção -execdir , que invoca rename dentro do diretório Test 01 e passa Test A como argumento. Você pode acelerar as coisas passando vários argumentos para rename em um lote, usando + em vez de ; para finalizar o comando -execdir .

find -depth -name '* *' -type d -execdir rename 'y/ /_/' {} +

Como alternativa, use este comando zsh curto, mas enigmático:

autoload zmv
zmv -Qw '**/*(/D)' '$1${2// /_}'

A zmv function renomeia os arquivos de acordo com os padrões. O padrão de origem é **/* , que corresponde a todos os arquivos ( * ) em todos os subdiretórios recursivamente ( **/ ). Os qualificadores de glob (ativados pela opção -Q ) indicam que apenas diretórios são correspondidos ( / ) e que os arquivos de ponto estão incluídos ( D ). A opção -w cria uma referência anterior para cada caractere curinga no padrão de origem. A substituição começa com $1 , que designa a correspondência para o primeiro caractere curinga (por ** , isso inclui um% final/) e é seguido por ${2// /_} , que é $2 (o que coincide * ) modificado para substituir todos os caracteres de espaço por _ . Adicione a opção -v para ver o que o comando faz, você notará que ele percorre a profundidade primeiro como find -depth .

    
por 26.08.2012 / 23:45