Manipular a string de retorno {} de find -exec

Manipular a string de retorno {} de find -exec

Quero fazer isso da maneira mais eficiente possível, caso haja muitos arquivos. O que eu quero é renomear todos os arquivos que encontrei e remover o sufixo.

Por exemplo:

[/tmp] $ ls -l
a.log
b.log
c.tmp
[/tmp] $ find /tmp -name "*.log" -type f -exec mv {} {%.*} \;
[/tmp] $ ls -l
a
b
c.tmp

Isso não funciona. Se fosse uma variável bash normal ${var%.*}teria retornado varaté o último ..

Responder1

Inicie um shell para usar operadores de expansão de parâmetros do shell:

find ~/tmp -name '*.log' -type f -exec sh -c '
  for file do
    mv -i -- "$file" "${file%.*}"
  done' sh {} +

Observe que você não deseja fazer isso em /tmpnenhum diretório gravável por terceiros, pois isso permitiria que usuários mal-intencionados fizessem você renomear .logarquivos arbitrários no sistema de arquivos¹ (ou mover arquivos para qualquer diretório²).

Com algumas findimplementações mv, você pode usar find -execdire mv -Tpara torná-lo mais seguro:

find /tmp -name '*.log' -type f -execdir sh -c '
  for file do
    mv -Ti -- "$file" "${file%.*}"
  done' sh {} +

Ou use rename(a variante perl) que apenas faria uma rename()chamada de sistema para não tentar mover arquivos para outros sistemas de arquivos ou diretórios ...

find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +

Ou faça tudo em perl:

perl -MFile::Find -le '
  find(
    sub {
      if (/\.log\z/) {
        $old = $_;
        s/\.log\z//;
        rename($old, $_) or warn "rename $old->$_: $!\n"
      }
    }, @ARGV)' ~/tmp

Mas observe que perl( Find::Fileao contrário do GNU find) não faz uma travessia segura de diretório³, então isso também não é algo que você gostaria de fazer /tmp.


Notas.

¹ um invasor pode criar um /tmp/. /auth.logarquivo e, entre findencontrá-lo e mvmovê-lo (e essa janela pode facilmente ficar arbitrariamente grande), substituir o "/tmp/. "diretório por um link simbólico para, /var/logresultando em /var/log/auth.logser renomeado para/var/log/auth

² Muito pior, um invasor pode criar um link /tmp/foo.logmalicioso, crontabpor exemplo, e /tmp/fooum link simbólico /etc/cron.de fazer você mover esse crontabem /etc/cron.d. Essa é a ambigüidade com mv(também se aplica cpe lnpelo menos) que pode ser tantomover paraemudar para. GNU mvcorrige isso com seu -t(em) e -T(para) opções.

³ File::Findpercorre o diretório fazendo chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..").... Assim, alguém pode criar um /tmp/foo/bardiretório e, no momento certo, renomeá-lo para /tmp/barque chdir("../..")você chegue ao /.

Responder2

Aqui está uma frase:

find /tmp -name "*.log" -type f -exec sh -c 'f="{}"; mv "$f" "${f%.*}"' \;

Ele inicia um shell, atribui {} a uma variável adequada dentro do shell e, em seguida, aplica as manipulações de string usando a sintaxe do shell.

informação relacionada