
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 var
até 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 /tmp
nenhum diretório gravável por terceiros, pois isso permitiria que usuários mal-intencionados fizessem você renomear .log
arquivos arbitrários no sistema de arquivos¹ (ou mover arquivos para qualquer diretório²).
Com algumas find
implementações mv
, você pode usar find -execdir
e mv -T
para 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::File
ao 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.log
arquivo e, entre find
encontrá-lo e mv
movê-lo (e essa janela pode facilmente ficar arbitrariamente grande), substituir o "/tmp/. "
diretório por um link simbólico para, /var/log
resultando em /var/log/auth.log
ser renomeado para/var/log/auth
² Muito pior, um invasor pode criar um link /tmp/foo.log
malicioso, crontab
por exemplo, e /tmp/foo
um link simbólico /etc/cron.d
e fazer você mover esse crontabem /etc/cron.d
. Essa é a ambigüidade com mv
(também se aplica cp
e ln
pelo menos) que pode ser tantomover paraemudar para. GNU mv
corrige isso com seu -t
(em) e -T
(para) opções.
³ File::Find
percorre o diretório fazendo chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
. Assim, alguém pode criar um /tmp/foo/bar
diretório e, no momento certo, renomeá-lo para /tmp/bar
que 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.