Voglio farlo nel modo più efficiente possibile nel caso in cui ci siano molti file.
Quello che voglio è rinominare tutti i file che ho trovato e rimuovere il loro suffisso.
Ad esempio:
[/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
Questo non funziona. Se fosse una normale variabile bash ${var%.*}
avrebbe restituito var
fino all'ultimo .
.
Risposta accettata:
Avvia una shell per utilizzare gli operatori di espansione dei parametri della shell:
find ~/tmp -name '*.log' -type f -exec sh -c '
for file do
mv -i -- "$file" "${file%.*}"
done' sh {} +
Nota che non vuoi farlo su /tmp
o qualsiasi directory scrivibile da altri in quanto ciò consentirebbe agli utenti malintenzionati di farti rinominare .log
arbitrario file sul file system¹ (o sposta i file in qualsiasi directory²).
Con alcuni find
e mv
implementazioni, puoi usare find -execdir
e mv -T
per renderlo più sicuro:
find /tmp -name '*.log' -type f -execdir sh -c '
for file do
mv -Ti -- "$file" "${file%.*}"
done' sh {} +
Oppure usa rename
(la variante perl) che farebbe semplicemente un rename()
chiamata di sistema quindi non tentare di spostare i file su altri filesystem o in directory...
find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +
Oppure fai tutto in perl
:
perl -MFile::Find -le '
find(
sub {
if (/\.log\z/) {
$old = $_;
s/\.log\z//;
rename($old, $_) or warn "rename $old->$_: $!\n"
}
}, @ARGV)' ~/tmp
Ma nota che perl
's Find::File
(contrariamente a GNU find
) non esegue un attraversamento sicuro delle directory³, quindi non è qualcosa che vorresti fare su /tmp
neanche.
Note.
¹ un utente malintenzionato può creare un /tmp/. /auth.log
file e tra find
trovarlo e mv
spostandolo (e quella finestra può essere facilmente resa arbitrariamente grande) sostituisci "/tmp/. "
directory con un collegamento simbolico a /var/log
risultante in /var/log/auth.log
rinominato in /var/log/auth
² Molto peggio, un utente malintenzionato può creare un /tmp/foo.log
crontab
dannoso per esempio e /tmp/foo
un collegamento simbolico a /etc/cron.d
e farti spostare quel crontab in /etc/cron.d
. Questa è l'ambiguità con mv
(si applica anche a cp
e ln
almeno) che possono essere entrambi sposta in e entrare in . GNU mv
lo risolve con il suo -t
(in ) e -T
(a ) opzioni.
³ File::Find
attraversa la directory eseguendo chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")...
. Quindi qualcuno può creare un /tmp/foo/bar
directory e, al momento opportuno, rinominarla in /tmp/bar
quindi chdir("../..")
ti porterebbe in /
.