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