GNU/Linux >> Tutoriales Linux >  >> Linux

Manipular {} Cadena de retorno de Find -exec?

Quiero hacerlo lo más eficientemente posible en caso de que haya muchos archivos.
Lo que quiero es cambiar el nombre de todos los archivos que encontré y eliminar su sufijo.

Por ejemplo:

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

Esto no funciona. Si fuera una variable bash normal ${var%.*} habría devuelto var hasta el último . .

Respuesta aceptada:

Inicie un shell para usar operadores de expansión de parámetros de shell:

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

Tenga en cuenta que no desea hacer eso en /tmp o cualquier directorio en el que otros puedan escribir, ya que eso permitiría a los usuarios maliciosos hacerle cambiar el nombre de .log arbitrario archivos en el sistema de archivos¹ (o mover archivos a cualquier directorio²).

Con algo de find y mv implementaciones, puede usar find -execdir y mv -T para hacerlo más seguro:

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

O use rename (la variante de perl) que simplemente haría un rename() llamada al sistema para no intentar mover archivos a otros sistemas de archivos o directorios...

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

O hazlo todo en perl :

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

Pero tenga en cuenta que perl ‘s Find::File (al contrario de GNU find ) no realiza un recorrido de directorio seguro³, por lo que no es algo que le gustaría hacer en /tmp tampoco.

Notas.

¹ un atacante puede crear un /tmp/. /auth.log archivo, y entre find encontrarlo y mv moviéndolo (y esa ventana puede hacerse fácilmente arbitrariamente grande) reemplace "/tmp/. " directorio con un enlace simbólico a /var/log resultando en /var/log/auth.log siendo renombrado a /var/log/auth

² Mucho peor, un atacante puede crear un /tmp/foo.log crontab malicioso por ejemplo y /tmp/foo un enlace simbólico a /etc/cron.d y hacer que muevas ese crontab a /etc/cron.d . Esa es la ambigüedad con mv (también se aplica a cp y ln al menos) que puede ser tanto mover a y mover a . GNU mv lo arregla con su -t (hacia ) y -T (a ) opciones.

Relacionado:¿Usar fecha variable en el comando Sed?

³ File::Find atraviesa el directorio haciendo chdir("/tmp"); read content; chdir("foo") ...; chdir("bar"); chdir("../..")... . Entonces alguien puede crear un /tmp/foo/bar directorio y en el momento adecuado, cámbiele el nombre a /tmp/bar entonces chdir("../..") te llevaría a / .


Linux
  1. ¿Cómo encontrar un archivo cuyo nombre incluye una cadena dada, como "abcde"?

  2. ¿Obteniendo la opción -exec en Find To Work?

  3. Escapar de los caracteres desconocidos de la cadena para -exec?

  4. Buscar y cambiar el nombre de un directorio

  5. adb:Encuentra PID desde el shell de adb

Cómo encontrar una cadena en un archivo en Linux

Cómo encontrar la versión de Virtualbox desde la línea de comandos en Linux

encontrar -exec cmd {} + vs | xargs

find -exec una función de shell en Linux?

¿Cómo encontrar la ruta completa del programa C++ Linux desde adentro?

bash - encuentra la posición del índice de cadena de la subcadena