Je veux le faire aussi efficacement que possible au cas où il y aurait beaucoup de fichiers.
Ce que je veux, c'est renommer tous les fichiers que j'ai trouvés et supprimer leur suffixe.
Par exemple :
[/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
Cela ne fonctionne pas. S'il s'agissait d'une variable bash normale ${var%.*}
aurait renvoyé var
jusqu'au dernier .
.
Réponse acceptée :
Démarrez un shell pour utiliser les opérateurs d'expansion des paramètres du shell :
find ~/tmp -name '*.log' -type f -exec sh -c '
for file do
mv -i -- "$file" "${file%.*}"
done' sh {} +
Notez que vous ne voulez pas faire cela sur /tmp
ou tout répertoire accessible en écriture par d'autres car cela permettrait à des utilisateurs malveillants de vous faire renommer arbitrairement .log
fichiers sur le système de fichiers¹ (ou déplacer des fichiers dans n'importe quel répertoire²).
Avec un peu de find
et mv
implémentations, vous pouvez utiliser find -execdir
et mv -T
pour le rendre plus sûr :
find /tmp -name '*.log' -type f -execdir sh -c '
for file do
mv -Ti -- "$file" "${file%.*}"
done' sh {} +
Ou utilisez rename
(la variante perl) qui ferait juste un rename()
appel système afin de ne pas tenter de déplacer des fichiers vers d'autres systèmes de fichiers ou dans des répertoires…
find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +
Ou faites le tout en perl
:
perl -MFile::Find -le '
find(
sub {
if (/\.log\z/) {
$old = $_;
s/\.log\z//;
rename($old, $_) or warn "rename $old->$_: $!\n"
}
}, @ARGV)' ~/tmp
Mais notez que perl
's Find::File
(contrairement à GNU find
) ne fait pas une traversée de répertoire sécurisée³, donc ce n'est pas quelque chose que vous aimeriez faire sur /tmp
soit.
Remarques.
¹ un attaquant peut créer un /tmp/. /auth.log
file, et entre find
le trouver et mv
le déplacer (et cette fenêtre peut facilement être rendue arbitrairement grande) remplacer le "/tmp/. "
répertoire avec un lien symbolique vers /var/log
résultant en /var/log/auth.log
renommé en /var/log/auth
² Bien pire, un attaquant peut créer un /tmp/foo.log
crontab
malveillant par exemple et /tmp/foo
un lien symbolique vers /etc/cron.d
et vous faire déplacer cette crontab dans /etc/cron.d
. C'est l'ambiguïté avec mv
(s'applique également à cp
et ln
au moins) qui peuvent être à la fois déplacer vers et emménager . GNU mv
le corrige avec son -t
(dans ) et -T
(à ) options.
³ File::Find
parcourt le répertoire en faisant chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
. Donc, quelqu'un peut créer un /tmp/foo/bar
répertoire et au bon moment, renommez-le en /tmp/bar
donc le chdir("../..")
vous amènerait dans /
.