I want to do it as efficient as possible in case there will be a lot of files.
What I want is rename all the files I found and remove their suffix.
For example:
[/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
This doesn't work. If it was a normal bash variable ${var%.*}
would have returned var
until the last .
.
Best Answer
Start a shell to use shell parameter expansion operators:
Note that you don't want to do that on
/tmp
or any directory writable by others as that would allow malicious users to make you rename arbitrary.log
files on the file system¹ (or move files into any directory²).With some
find
andmv
implementations, you can usefind -execdir
andmv -T
to make it safer:Or use
rename
(the perl variant) that would just do arename()
system call so not attempt to move files to other filesystems or into directories...Or do the whole thing in
perl
:But note that
perl
'sFind::File
(contrary to GNUfind
) doesn't do a safe directory traversal³, so that's not something you would like to do on/tmp
either.Notes.
¹ an attacker can create a
/tmp/. /auth.log
file, and in betweenfind
finding it andmv
moving it (and that window can easily be made arbitrarily large) replace the"/tmp/. "
directory with a symlink to/var/log
resulting in/var/log/auth.log
being renamed to/var/log/auth
² A lot worse, an attacker can create a
/tmp/foo.log
maliciouscrontab
for example and/tmp/foo
a symlink to/etc/cron.d
and make you move that crontab into/etc/cron.d
. That's the ambiguity withmv
(also applies tocp
andln
at least) that can be both move to and move into. GNUmv
fixes it with its-t
(into) and-T
(to) options.³
File::Find
traverses the directory by doingchdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
. So someone can create a/tmp/foo/bar
directory and at the right moment, rename it to/tmp/bar
so thechdir("../..")
would land you in/
.