combinando buscar con otros comandos: ¿cuándo usar -exec y cuándo usar pipe?

combinando buscar con otros comandos: ¿cuándo usar -exec y cuándo usar pipe?

Aprendí a usar el comando buscar por sí solo para buscar archivos y directorios; sin embargo, cuando se trata de hacer algo con los archivos/carpetas, estoy confundido.

Dado el siguiente comando:

find . -type f -iname "*.cr2" 

Si quiero copiar los archivos que se encuentran arriba en un nuevo directorio, naturalmente pensaría en usar copy( cp) y pipe |.

find . -type f -iname "*.cr2" | cp \destination_directory

Y para mí, esto colocaría todas mis fotos en un disco completo y las anidaría en niveles de subcarpetas en una sola carpeta lista para comenzar a organizar.

Sin embargo, la gente sigue diciéndome que use el -execparámetro, así que mi pregunta es ¿cómo puedo saber cuándo canalizar |y cuándo usar -execel comando como se muestra a continuación?

 find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;

EDITAR

La solución sugerida (a continuación) solo copia archivos cuyos nombres son únicos. y dice que cp no copiará file.txt y lo reemplazará con file.txt. En el caso de que copie muchos archivos y no sepa si habrá archivos con el mismo nombre, ¿cómo copia algo y dice cambiarle el nombre si el nombre del archivo existe?

Solución sugerida

find . -type f -iname "*.txt" -print0 | xargs -0 cp -t /home/josh/Documents/copy/

/home/josh/documents/copy es el directorio al que quiero mover cosas.

Respuesta1

Hay errores en sus suposiciones, pero primero algunos antecedentes:

Debes discernir dos usos de -exec:

  • con \;el {} será reemplazado por un solo elemento encontrado
  • con +será {}reemplazado por muchos elementos (tantos como la línea de comando pueda contener).

Por lo tanto, su ejemplo de -execuso invoca tantos cpcomandos como elementos encontrados por find.

Usar find ... -exec cmd {} ... +es similar en eficiencia a canalizar la salida de find a un comando que maneja múltiples nombres de entrada.

También debe tener en cuenta que -execmaneja bien los nombres de archivos/rutas con espacios, pero cuando canaliza la salida de find a otro programa, eso puede causar problemas. Por lo tanto, a algunos programas que esperan una lista de nombres de archivos de la entrada estándar se les puede dar la opción de tener esos nombres de archivos separados por NUL (a menudo -0o --null). Y findtiene una opción para pasarlos al siguiente programa de esa manera especificando:-print0


Ahora pasando a tus ejemplos:

find . -type f -iname "*.cr2" | cp destination_directory

no copia los archivos encontrados, ya que cp no lee la entrada estándar. Tendrías que usar:

find . -type f -iname "*.cr2" | xargs cp -t destination_directory

o para manejar los caminos con espacios:

find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory

Con aproximadamente la misma eficiencia podrías hacer:

find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +

(Como señaló G-Man, {}tiene que estar al final, antes de +) Todo lo anterior nonoconstruyo la jerarquía bajo el directorio de destino para eso y por costumbre, incluso si el directorio de origen es plano, me encuentro usando cpioen su lugar:

find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory

que enumera muy bien lo que está haciendo a lo largo del camino.


Las partes relevantes de man find:

-exec command ;
       Execute command; true if 0 status is returned.   All  following
       arguments  to  find  are  taken  to be arguments to the command
       until an argument consisting of `;' is encountered.  The string
       `{}'  is  replaced  by  the  current  file name being processed
       everywhere it occurs in the arguments to the command, not  just
       in  arguments  where  it is alone, as in some versions of find.
       Both of these constructions might need to be  escaped  (with  a
       `\')  or  quoted  to  protect them from expansion by the shell.
       See the EXAMPLES section for examples of the use of  the  -exec
       option.   The  specified  command  is run once for each matched
       file.  The command  is  executed  in  the  starting  directory.
       There  are unavoidable security problems surrounding use of the
       -exec action; you should use the -execdir option instead.

-exec command {} +
       This variant of the -exec action runs the specified command  on
       the  selected files, but the command line is built by appending
       each selected file name at the end; the total number of invoca‐
       tions  of  the  command  will  be  much less than the number of
       matched files.  The command line is built in much the same  way
       that xargs builds its command lines.  Only one instance of `{}'
       is allowed within the command.  The command is executed in  the
       starting directory.

información relacionada