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 -exec
parámetro, así que mi pregunta es ¿cómo puedo saber cuándo canalizar |
y cuándo usar -exec
el 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 -exec
uso invoca tantos cp
comandos 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 -exec
maneja 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 -0
o --null
). Y find
tiene 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 cpio
en 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.