Por que “find / -name '* .txt' | cp / junk ”não funciona?

0

Se eu quiser encontrar algum arquivo com .txt no nome, e para cada correspondência encontrada copiá-lo para a pasta / junk, o seguinte pode ser considerado como trabalho;

find / -name "*.txt" | cp /junk

mas isso não funcionará porque o find produzirá os resultados como uma lista, que não pode ser inserida no cp.

Então eu poderia usar o xargs para resolver isso

find / -name "*.txt" | xargs cp /junk

Porque xargs mudará a lista em uma linha que pode ser alimentada em cp. Eu também acho que este comando terminaria completamente a busca pelos arquivos, 'produza a lista', e só então rodaria o lado direito do pipe (a cópia).

Como alternativa (e de preferência) eu poderia usar exec

find / -name ".txt" -exec cp {} /junk \;

O qual executaria a cópia toda vez que uma correspondência fosse encontrada (e executaria a cópia em um processo separado, para que o comando find continuasse sendo executado em paralelo).

Alguém pode confirmar que esses comandos e meu entendimento estão corretos?

Devo acrescentar que isto é apenas para fins de educação, isto não é um cenário da vida real.

    
por microscope 31.01.2017 / 22:19

1 resposta

7

  1. Sim, find / -name "*.txt" | cp /junk não funcionará porque cp não lê seus argumentos de stdin.
  2. Não, find / -name "*.txt" | xargs cp /junk também não funcionará porque xargs anexará os argumentos que lê de stdin ao comando, portanto, cp tentaria copiar na direção errada. (Você pode tentar corrigir isso com a opção -I para xargs , mas você pode simplesmente usar find -exec .)
  3. Sim, find / -name ".txt" -exec cp {} /junk \; funcionará, mas usará uma chamada de cp para cada arquivo (e iniciará esse comando assim que o arquivo for encontrado).

Você também pode tentar esta solução, eu deveria iniciar apenas uma invocação de cp (ou pelo menos começará o mínimo possível, o comprimento da linha de comando é limitado):

find / -path /junk -prune -or -name '*.txt' -print0 | xargs -0 sh -c 'cp "$@" /junk'

Como @don_chrissti comentou, você pode usar cp -t se tiver o cp do GNU. Então pode ser feito assim

find / -path /junk -prune -or -name '*.txt' -print0 | xargs -0 cp -t /junk

ou até mesmo

find / -path /junk -prune -or -name '*.txt' -exec cp -t /junk {} +

Todos os três irão coletar tantos argumentos quanto caber na linha de comando e executar o mínimo de cp possível. Mas ainda pode ser o caso de um cp ser iniciado antes de find ser feito, então temos que excluir /junk caso contrário, ele poderá encontrar as cópias.

    
por 31.01.2017 / 22:43