GNU/Linux >> Znalost Linux >  >> Linux

Manipulovat {} Vrátit řetězec z Find -exec?

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.

Související:Použít proměnné datum v příkazu Sed?

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


Linux
  1. Najděte geolokaci IP adresy z příkazového řádku

  2. Najděte počet řádků kódu z úložiště GitHub

  3. Jak najít soubor, jehož název obsahuje daný řetězec, například „abcde“?

  1. Získání možnosti -exec v aplikaci Najít do práce?

  2. Vymanit se z hledání, pokud selže -exec?

  3. Uniknout neznámým znakům z řetězce pro -exec?

  1. Jak přejmenovat více souborů pomocí funkce Najít?

  2. najít -exec funkci shellu v Linuxu?

  3. Jak najít úplnou cestu k programu C++ Linux zevnitř?