Determina se o arquivo está sendo gravado?

22

Eu preciso implantar um processo automatizado (através de 1 min cron script) que procura por arquivos tar em um diretório específico. Se um arquivo tar for encontrado, ele será descompactado para o local apropriado e, em seguida, o arquivo tar será excluído.

Os arquivos tar são automaticamente copiados para este servidor através do SSH de outro servidor. Em alguns casos, os arquivos tar são extremamente grandes, com muitos arquivos.

O problema que estou esperando encontrar: se for necessário > 1 minuto para o arquivo tar ser copiado para o servidor, e o script cron é executado uma vez a cada minuto, ele verá o arquivo .tar.gz e tentará descompactá-lo, mesmo que o arquivo tar ainda esteja no processo de sendo escrito para.

Existe alguma maneira (através de comandos bash) para testar se um arquivo está sendo gravado no momento, ou se é apenas um arquivo parcial, etc?

Uma alternativa que eu estava pensando era que o arquivo fosse copiado como uma extensão de arquivo diferente (como .tar.gz.part ) e depois renomeado para .tar.gz após a conclusão da transferência. Mas imaginei que tentaria descobrir se há simplesmente uma maneira de determinar se o arquivo é inteiro na linha de comando primeiro ... Alguma pista?

    
por Jake Wilson 08.08.2012 / 18:03

5 respostas

9

Você está no caminho certo, renomear o arquivo é uma operação atômica, então realizar a renomeação após o upload é simples, elegante e não propenso a erros. Outra abordagem que posso pensar é usar lsof | grep filename.tar.gz para verificar se o arquivo está sendo acessado por outro processo.

    
por 08.08.2012 / 18:08
13

Sua melhor aposta é usar lsof para determinar se um arquivo foi aberto por qualquer processo:

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

Você não pode dizer facilmente se está em processo de gravação, mas se está sendo escrito, deve estar aberto.

Editar: vamos resolver o problema real aqui em vez de tentar implementar a solução proposta!

Use o rsync para transferir o arquivo:

○ → rsync -e ssh remote:big.tar.gz .

Dessa forma, o arquivo não será copiado por cima do arquivo existente, mas copiado em um arquivo temporário ( .big.tar.gz.XXXXXX ) até que a transferência seja concluída e, em seguida, movida para o lugar.

    
por 08.08.2012 / 18:09
5

A melhor maneira de fazer isso é usar incron ("inotify cron sistema"). Ele permite que você defina um inotify para assistir em um diretório que, em seguida, notificará você operações de arquivo. Nesse caso, você deve observar o diretório para um close_write. Isso permitirá que você execute seu comando assim que o arquivo for fechado após a gravação.

    
por 08.08.2012 / 18:36
3

Um pouco antigo, mas a maioria das respostas ignora completamente o ponto da pergunta:

But I figured I'd try to figure out if there is simply a way to determine if the file is whole at the command line first...

Em geral, não há. Você simplesmente não tem informações suficientes para determinar isso.

Porque determinar que o arquivo é fechado não é o mesmo que determinar se o arquivo é inteiro . Por exemplo, um arquivo será "fechado" se a conexão for perdida no meio da transferência.

Apenas a resposta de @ Alex acertou. E até ele caiu por usar lsof .

Para determinar se o arquivo foi totalmente transferido com sucesso, é necessário mais dados. Tais como:

One alternative I was thinking of was to have the file be copied as a different file extension (like .tar.gz.part) and then renamed to .tar.gz after the transfer is complete.

Essa é uma maneira perfeita de comunicar que o arquivo foi totalmente transferido com sucesso. Você também pode mover arquivos de um diretório para outro, desde que permaneça dentro do mesmo sistema de arquivos. Ou peça ao remetente que envie um arquivo filename.done vazio para sinalizar a conclusão.

Mas todos os métodos têm que confiar no remetente de alguma forma sinalizando que a transferência foi concluída com sucesso. Porque apenas o remetente tem essa informação.

Alguns formatos de arquivo (como PDFs) contêm dados que permitem determinar se o arquivo está completo. Mas você tem que abrir e ler praticamente todo o arquivo para descobrir.

lsof apenas informará que o arquivo não está mais aberto - ele não informará por que ele não está mais aberto. Também não vai dizer o tamanho do arquivo.

    
por 20.04.2018 / 20:31
2

Parece que o lsof pode detectar em que modo um arquivo está aberto:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

Veja onde diz 1w? Isso significa que o número do descritor de arquivo é 1 e o modo é w ou escreve.

    
por 26.07.2015 / 04:57