GNU/Linux >> Linux Esercitazione >  >> Linux

Manipola {} Restituisce la stringa da Find -exec?

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.

Correlati:utilizzare la data variabile nel comando Sed?

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


Linux
  1. Trova il numero di righe di codice dal repository GitHub

  2. Shell test per trovare un motivo in una stringa?

  3. Trova -exec + Vs Trova | Xargs:quale scegliere?

  4. Rompere la ricerca se un -exec fallisce?

  5. Come rinominare più file usando Trova?

Come trovare una stringa in un file su Linux

Come trovare la versione di Virtualbox dalla riga di comando in Linux

trova -exec cmd {} + vs | xargs

Escludi elenco di file da find

bash - trova la posizione dell'indice della stringa della sottostringa

trova il comando dal PID