GNU/Linux >> Tutoriels Linux >  >> Linux

Manipuler la chaîne de retour {} à partir de Find -exec ?

Je veux le faire aussi efficacement que possible au cas où il y aurait beaucoup de fichiers.
Ce que je veux, c'est renommer tous les fichiers que j'ai trouvés et supprimer leur suffixe.

Par exemple :

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

Cela ne fonctionne pas. S'il s'agissait d'une variable bash normale ${var%.*} aurait renvoyé var jusqu'au dernier . .

Réponse acceptée :

Démarrez un shell pour utiliser les opérateurs d'expansion des paramètres du shell :

find ~/tmp -name '*.log' -type f -exec sh -c '
  for file do
    mv -i -- "$file" "${file%.*}"
  done' sh {} +

Notez que vous ne voulez pas faire cela sur /tmp ou tout répertoire accessible en écriture par d'autres car cela permettrait à des utilisateurs malveillants de vous faire renommer arbitrairement .log fichiers sur le système de fichiers¹ (ou déplacer des fichiers dans n'importe quel répertoire²).

Avec un peu de find et mv implémentations, vous pouvez utiliser find -execdir et mv -T pour le rendre plus sûr :

find /tmp -name '*.log' -type f -execdir sh -c '
  for file do
    mv -Ti -- "$file" "${file%.*}"
  done' sh {} +

Ou utilisez rename (la variante perl) qui ferait juste un rename() appel système afin de ne pas tenter de déplacer des fichiers vers d'autres systèmes de fichiers ou dans des répertoires…

find /tmp -name '*.log' -type f -execdir rename 's/\.log$//' {} +

Ou faites le tout en perl :

perl -MFile::Find -le '
  find(
    sub {
      if (/\.log\z/) {
        $old = $_;
        s/\.log\z//;
        rename($old, $_) or warn "rename $old->$_: $!\n"
      }
    }, @ARGV)' ~/tmp

Mais notez que perl 's Find::File (contrairement à GNU find ) ne fait pas une traversée de répertoire sécurisée³, donc ce n'est pas quelque chose que vous aimeriez faire sur /tmp soit.

Remarques.

¹ un attaquant peut créer un /tmp/. /auth.log file, et entre find le trouver et mv le déplacer (et cette fenêtre peut facilement être rendue arbitrairement grande) remplacer le "/tmp/. " répertoire avec un lien symbolique vers /var/log résultant en /var/log/auth.log renommé en /var/log/auth

² Bien pire, un attaquant peut créer un /tmp/foo.log crontab malveillant par exemple et /tmp/foo un lien symbolique vers /etc/cron.d et vous faire déplacer cette crontab dans /etc/cron.d . C'est l'ambiguïté avec mv (s'applique également à cp et ln au moins) qui peuvent être à la fois déplacer vers et emménager . GNU mv le corrige avec son -t (dans ) et -T (à ) options.

En relation :Utiliser une date variable dans la commande Sed ?

³ File::Find parcourt le répertoire en faisant chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")... . Donc, quelqu'un peut créer un /tmp/foo/bar répertoire et au bon moment, renommez-le en /tmp/bar donc le chdir("../..") vous amènerait dans / .


Linux
  1. Trouver la géolocalisation d'une adresse IP à partir de la ligne de commande

  2. Trouver le nombre de lignes de code à partir du référentiel GitHub

  3. Rechercher -exec + Vs Rechercher | Xargs :lequel choisir ?

  4. trouver -exec une fonction shell sous Linux ?

  5. Comment trouver le chemin complet du programme Linux C++ de l'intérieur ?

Comment trouver une chaîne dans un fichier sous Linux

Comment trouver la version de Virtualbox à partir de la ligne de commande sous Linux

trouver -exec cmd {} + vs | xarg

Rechercher et renommer un répertoire

Exclure la liste des fichiers de la recherche

bash - trouve la position de l'index de chaîne de la sous-chaîne