Como posso encontrar arquivos e depois usar o xargs para movê-los?

28

Quero encontrar alguns arquivos e movê-los.

Eu posso encontrar o arquivo com:

$ find /tmp/ -ctime -1 -name x*

Eu tentei movê-los para o meu ~/playdiretório com:

$ find /tmp/ -ctime -1 -name x* | xargs mv ~/play/

mas isso não funcionou. Obviamente, mv precisa de dois argumentos.
Não tem certeza se (ou como) fazer referência ao 'item atual' do xargs no comando mv?

Michael Durrant
fonte
3
Por quê? Você pode usar o espaço reservado com -I: find . | xargs -I'{}' mv '{}' ~/play/, mas como homem diz, que “implica -xe -L 1.” Então, nenhum ganho. Melhor mantê-lo simples e usofind . -exec mv '{}' ~/play/ \;
manatwork
Por favor, poste como resposta para ver votos, se você não se importaria :)
Michael Durrant
Apenas perguntei o seu motivo, pois tive a sensação de que não entendi o ponto. Se Drav Sloan acrescentar a nota sobre as opções implícitas, sua resposta será a melhor que eu poderia escrever. Então é melhor ir com isso.
manatwork
possível duplicata do padrão Localizar e mover
slm
@manatwork Eu editei a minha resposta para refletir os pontos duder :)
Drav Sloan

Respostas:

43

Olhe para a resposta de Stephane para o melhor método, dê uma olhada na minha resposta por razões para não usar as soluções mais óbvias (e razões pelas quais elas não são as mais eficientes).

Você pode usar a -Iopção de xargs:

find /tmp/ -ctime -1 -name "x*" | xargs -I '{}' mv '{}' ~/play/

Que funciona em um mecanismo semelhante ao finde {}. Eu também citaria seu -nameargumento (porque um arquivo que começa com xo diretório atual seria envolto em um arquivo e passado como argumento a ser encontrado - o que não dará o comportamento esperado!).

No entanto, conforme indicado pelo manatwork, conforme detalhado na xargspágina do manual:

   -I replace-str
          Replace occurrences of replace-str in the initial-arguments with
          names read from standard input.  Also, unquoted  blanks  do  not
          terminate  input  items;  instead  the  separator is the newline
          character.  Implies -x and -L 1.

O importante a ser observado é que isso -L 1significa que apenas uma linha de saída findserá processada por vez. Isso significa que é sintaticamente o mesmo que:

find /tmp/ -ctime -1 -name "x*" -exec mv '{}' ~/play/

(que executa uma única mvoperação para cada arquivo).

Mesmo usando o -0argumento GNU xargs e o find -print0argumento causa exatamente o mesmo comportamento de -I- isto é para clone()um processo para cada arquivo mv:

find . -name "x*" -print0 | strace xargs -0 -I '{}' mv '{}' /tmp/other

.
.
read(0, "./foobar1/xorgslsala11\0./foobar1"..., 4096) = 870
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =     0x7fbb82fad000
open("/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=26066, ...}) = 0
mmap(NULL, 26066, PROT_READ, MAP_SHARED, 3, 0) = 0x7fbb82fa6000
close(3)                                = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 661
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 661
--- SIGCHLD (Child exited) @ 0 (0) ---
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,         child_tidptr=0x7fbb835af9d0) = 662
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 662
--- SIGCHLD (Child exited) @ 0 (0) ---
.
.
.
Drav Sloan
fonte
Isso pressupõe que os nomes dos arquivos não contenham caracteres de nova linha, aspas simples, aspas duplas ou barra invertida.
Stéphane Chazelas
17

Com as ferramentas GNU:

find /tmp/ -ctime -1 -name 'x*' -print0 |
  xargs -r0 mv -t ~/play/

A opção -t( --target) é específica do GNU. -print0, -r, -0, Enquanto não-padrão e originários de GNU também são encontrados em algumas outras implementações como em alguns BSDs.

POSIXly:

find /tmp/ -ctime -1 -name 'x*' -exec sh -c '
  exec mv "$@" ~/play/' sh {} +

Ambos executam o mvmenor número de comandos necessários e funcionam com qualquer caractere que os nomes dos arquivos possam conter. O GNU pode ter a vantagem de findcontinuar procurando arquivos enquanto mvcomeça a mover o primeiro lote.

Cuidado para que todos os arquivos e diretórios acabem em um diretório, cuidado com os confrontos se vários arquivos em diretórios diferentes tiverem o mesmo nome.

Stéphane Chazelas
fonte
Esta solução tem um desempenho muito melhor, pois chama mvuma vez para todos os argumentos (ou para todos -Lou -n, se fornecidos). Caso contrário, a chamada mvpara cada arquivo ficará antiga (e lenta) rapidamente.
R2evans
1

Talvez este comando seja possível agora e não estava em 2013, mas funciona perfeitamente para mim:

ls pattern* | xargs mv -t DESTINATION/

A -tchave coloca a pasta de destino em primeiro lugar, liberando o mvcomando para que todos os últimos argumentos sejam apenas os arquivos a serem movidos.

Nikhil VJ
fonte
11
esta foi a solução mais simples que funcionou para mim
ptetteh227 22/08
0

Você pode tentar com o comando abaixo e testado e funcionou bem

find /tmp/ -ctime -1 -type f -name "x*" -exec mv -t ~/play/ {} \;
Praveen Kumar BS
fonte