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 / .