Como copiar todos os arquivos em uma pasta, excluindo os arquivos que estão sendo gravados?

12

Eu faço o download de vários arquivos em uma pasta downloadingvia HTTPie . Um script bash tem como objetivo processar arquivos baixados, e tentei copiar os arquivos baixados para outra pasta como

find /folder/downloading -type f -exec mv '{}' /folder/downloaded \;

mas isso também copia os arquivos que ainda não foram finalizados. Tentei limitar a transferência para arquivos mais antigos adicionando -mmin +5ao comando. Qual é o comando eficiente para deixar os arquivos que estão sendo gravados e transferir apenas os arquivos baixados?

Googlebot
fonte
Se estiver copiando para o mesmo sistema de arquivos e você definir o downloader para não renomear (faça o download para %.partrenomear para%). Então, se o downloader for bem comportado (não faz mais nada estranho), você poderá renomear os mvarquivos ( ).
Ctrl-alt-delor
1
Que tipo de processamento você está tentando fazer? Provavelmente, existe uma opção muito mais simples disponível, como usar um pipeline.
Gardenhead

Respostas:

11

Não é muito eficiente, mas você pode fazer:

find /folder/downloading -type f -exec sh -c '
  for file do
    lsof -F a "$file" | grep -q w || mv "$file" /folder/downloaded
  done' sh {} +

Isso é verificar que o arquivo não está listado com um writo amodo cesso no li st de ocaneta files antes de mo vING.

A psmiscimplementação fusernormalmente encontrada em sistemas operacionais baseados em Linux tem uma -wfunção (verificar arquivos abertos para gravação), mas infelizmente ela só funciona -kpara eliminar os processos correspondentes. No entanto, parece que você ainda pode usá-lo usando o pseudo-sinal 0 que não faz nada:

find /folder/downloading -type f -exec sh -c '
  for file do
    fuser -s -w -k -0 "$file"  || mv "$file" /folder/downloaded
  done' sh {} +

Remova o -s(ou mesmo substitua-o -v) se desejar ver quais processos estão impedindo a movimentação.

Observe que, se você não estiver executando esses comandos como superusuário, receberá apenas informações sobre seus processos. Se os processos de download dos arquivos estiverem sendo executados como um usuário diferente, eles permanecerão não detectados.

Observe também que, a menos que você esteja movendo os arquivos para um sistema de arquivos diferente, a movimentação dos arquivos não impedirá que qualquer processo que esteja gravando atualmente no arquivo termine de gravá-lo.

No entanto, dependendo do que eles foram projetados para fazer depois, eles podem ser confundidos se, depois de terminar de escrever, o arquivo não está lá (por exemplo, se eles querem mudar alguns atributos do arquivo depois de baixá-lo e fazê-lo não através do descritor de arquivo (como chmod()vs fchmod(), ou utimes()que não pode ser feito por meio de um descritor de arquivo)).

Stéphane Chazelas
fonte
Pergunta do Shell: Acho que entendi seu código com uma exceção. Ele -execestá sendo executado shcom um comando ( -c '...') e {} +diz para colocar mais de um resultado nesse comando por vez. O que não entendo é por que há outro shapós o comando. o que estou perdendo?
Joe
2
@ Joe, é isso que entra no script embutido $0. Ou seja, atribui um nome a esse script embutido. Esse nome pode ser usado em mensagens de erro como, <name>: fuser: command not foundpor exemplo, shgeralmente é uma boa opção nesse caso para deixar claro o que está relatando essa mensagem de erro (também é o que seria se não apresentássemos nenhum argumento depois do script embutido).
Stéphane Chazelas