Aprendi a usar o comando find sozinho para localizar arquivos e diretórios, mas quando se trata de fazer algo com os arquivos/pastas, fico confuso.
Dado o seguinte comando:
find . -type f -iname "*.cr2"
Se eu quiser copiar os arquivos encontrados acima para um novo diretório, naturalmente pensaria em usar copy( cp
) e pipe |
.
find . -type f -iname "*.cr2" | cp \destination_directory
E para mim, isso colocaria todas as minhas fotos em uma unidade inteira e aninhadas em níveis de subpastas em uma única pasta, pronta para começar a organizar.
Porém as pessoas continuam me dizendo para usar o -exec
parâmetro, então minha pergunta é como saber quando canalizar |
e quando usar -exec
o comando abaixo?
find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;
EDITAR
A solução sugerida (abaixo) copia apenas arquivos cujos nomes de arquivo são exclusivos. e diz que cp não copiará file.txt e substituirá por file.txt. No caso de você copiar muitos arquivos e não saber se haverá arquivos com o mesmo nome, como copiar algo e dizer para renomeá-lo se o nome do arquivo existir?
Solução sugerida
find . -type f -iname "*.txt" -print0 | xargs -0 cp -t /home/josh/Documents/copy/
/home/josh/documents/copy sendo o diretório para o qual quero mover as coisas.
Responder1
Existem erros em suas suposições, mas primeiro alguns antecedentes:
Você deve discernir dois usos de -exec
:
- com
\;
o{}
será substituído por um único item encontrado - com
+
o{}
será substituído por muitos itens (tantos quanto a linha de comando puder conter).
Portanto, seu exemplo de -exec
uso invoca tantos cp
comandos quantos itens encontrados por find
.
Usar find ... -exec cmd {} ... +
é semelhante em eficiência a canalizar a saída de find para um comando que lida com vários nomes de entrada.
Você também deve levar em consideração que -exec
lida bem com nomes de arquivos/caminhos com espaços, mas quando você canaliza a saída de find para outro programa, isso pode causar problemas. Portanto, alguns programas que esperam uma lista de nomes de arquivos do stdin podem ter a opção de separar esses nomes de arquivos por NUL (geralmente -0
ou --null
). E find
tem a opção de fornecê-los ao próximo programa dessa forma, especificando:-print0
Agora chegando aos seus exemplos:
find . -type f -iname "*.cr2" | cp destination_directory
não copia os arquivos encontrados, pois cp não lê a entrada padrão. Você teria que usar:
find . -type f -iname "*.cr2" | xargs cp -t destination_directory
ou para lidar com os caminhos com espaços:
find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory
Com aproximadamente a mesma eficiência que você poderia fazer:
find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +
(Como G-Man apontou, {}
deve estar no final, antes do +
) Todas as opções acima fazemnãoconstrua a hierarquia no diretório de destino para isso e, por hábito, mesmo que o diretório de origem seja simples, acabo usando cpio
:
find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory
que lista bem o que está fazendo ao longo do caminho.
As 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.