combinando find com outros comandos: when to use -exec e when to use pipe? [duplicado]

7

Eu aprendi a usar o comando find por si só para encontrar arquivos e diretórios, mas quando se trata de fazer algo com os arquivos / pastas estou confuso.

Dado o seguinte comando:

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

Se eu quiser copiar os arquivos encontrados acima para um novo diretório, eu pensaria naturalmente 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.

No entanto, as pessoas continuam me dizendo para usar o parâmetro -exec , então minha pergunta é como você sabe quando canalizar | e quando usar o comando -exec como abaixo?

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

EDITAR

A solução sugerida (abaixo) apenas copia arquivos em que os nomes de arquivos são exclusivos. e diz que o cp não copiará o arquivo.txt e o substituirá pelo arquivo.txt. Na instância, você copia muitos arquivos e não sabe se haverá arquivos com o mesmo nome, como copiar algo e dizer 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.

    
por yoshiserry 07.10.2014 / 12:36

1 resposta

12

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 quantos a linha de comando pode conter).

Portanto, seu exemplo de -exec use invoca o comando cp como itens encontrados por find .

Usar find ... -exec cmd {} ... + é semelhante em eficiência ao direcionar a saída de encontrar para um comando que lida com vários nomes de entrada.

Você também deve levar em conta que -exec manipula bem nomes de arquivos / caminhos com espaços, mas quando você canaliza na saída de um outro programa que pode causar problemas. Portanto, alguns programas que esperam uma lista de nomes de arquivos de stdin podem ter uma opção para ter esses nomes de arquivos separados por NUL (geralmente -0 ou --null ). E o find tem a opção de fornecê-los ao próximo programa, especificando: -print0

Agora vamos ao seu exemplo:

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

não copia os arquivos encontrados, pois o CP não lê a entrada padrão. Você teria que usar:

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

ou para manipular os caminhos com espaços:

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

Com a mesma eficiência que você poderia fazer:

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

(Como o G-Man apontou, o {} tem que ser no final, antes do + ) Todos os itens acima fazem não construir a hierarquia sob o diretório de destino para isso e fora do hábito longo, mesmo se o diretório de origem é simples, eu me encontro usando cpio :

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

que lista muito 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.
    
por 07.10.2014 / 13:24