Chci to udělat co nejefektivněji pro případ, že tam bude hodně souborů.
Chci přejmenovat všechny soubory, které jsem našel, a odstranit jejich příponu.
Například:
[/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
Toto nefunguje. Pokud by to byla normální bash proměnná ${var%.*}
by vrátil var
až do posledního .
.
Přijatá odpověď:
Spusťte shell pro použití operátorů rozšíření parametrů shellu:
find ~/tmp -name '*.log' -type f -exec sh -c '
for file do
mv -i -- "$file" "${file%.*}"
done' sh {} +
Všimněte si, že to nechcete dělat na /tmp
nebo jakýkoli adresář, do kterého mohou zapisovat ostatní, protože by to umožnilo uživatelům se zlými úmysly přimět vás přejmenovat libovolný .log
soubory v systému souborů¹ (nebo přesuňte soubory do libovolného adresáře²).
S trochou find
a mv
implementací, můžete použít find -execdir
a mv -T
aby to bylo bezpečnější:
find /tmp -name '*.log' -type f -execdir sh -c '
for file do
mv -Ti -- "$file" "${file%.*}"
done' sh {} +
Nebo použijte rename
(varianta perlu), která by provedla pouze rename()
systémové volání, takže se nepokoušejte přesunout soubory do jiných souborových systémů nebo do adresářů…
find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +
Nebo to celé proveďte v perl
:
perl -MFile::Find -le '
find(
sub {
if (/\.log\z/) {
$old = $_;
s/\.log\z//;
rename($old, $_) or warn "rename $old->$_: $!\n"
}
}, @ARGV)' ~/tmp
Ale všimněte si, že perl
's Find::File
(na rozdíl od GNU find
) neprovádí bezpečné procházení adresářů³, takže to není něco, co byste chtěli dělat na /tmp
buď.
Poznámky.
¹ Útočník může vytvořit /tmp/. /auth.log
soubor a mezi find
jeho nalezení a mv
jeho posunutím (a toto okno lze snadno libovolně zvětšit) nahraďte "/tmp/. "
adresář se symbolickým odkazem na /var/log
výsledkem je /var/log/auth.log
přejmenován na /var/log/auth
² Mnohem horší je, že útočník může vytvořit soubor /tmp/foo.log
škodlivý crontab
například a /tmp/foo
symbolický odkaz na /etc/cron.d
a donutí vás přesunout ten crontab do /etc/cron.d
. To je nejednoznačnost s mv
(platí také pro cp
a ln
alespoň), které mohou být obě přesunout do a přesunout se do . GNU mv
opraví to pomocí -t
(do ) a -T
(do ) možnosti.
³ File::Find
projde adresář provedením chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
. Někdo tedy může vytvořit /tmp/foo/bar
adresář a ve správný okamžik jej přejmenujte na /tmp/bar
takže chdir("../..")
by vás dostal do /
.