tee -a não recria o arquivo

tee -a não recria o arquivo

Estou executando o seguinte comando em uma versão mais recente do Raspberry Pi 3 Debian:

cat /dev/ttyUSB0 | tee -a /media/pi/KINGSTON/klima.out | grep -F $ | tee -a /media/pi/KINGSTON/log

O comando funciona bem e faz o que deveria; entretanto, quando eu excluo (manualmente ou por CRON) o klima.outarquivo, ele não é recriado. O comando continua em execução, o arquivo de log continua sendo anexado, mas o klima.outarquivo não volta. (também sem buffer). Quero excluí-lo uma vez por semana para não deixá-lo crescer além de todos os limites. Alguma sugestão?

Responder1

Presumo que seu pipeline esteja em execução há muito tempo e que você esteja tentando remover o arquivo de log enquanto ele está em execução.

Ao excluir o arquivo, o teeprocesso ainda o mantém aberto para gravação, o que significa que o espaço em disco não é devolvido ao sistema. Isso não acontecerá até que todos os descritores de arquivo abertos que fazem referência ao arquivo sejam fechados.

É perfeitamente normal gravar em um arquivo que foi excluído, desde que o descritor de arquivo tenha sido alocado antes da exclusão.

Você terá que reiniciar o pipeline para que o arquivo seja recriado e para permitir que o espaço ocupado pelo arquivo de log antigo (agora sem nome) seja recuperado.

Para evitar ter que reiniciar o pipeline, você pode optar portruncaro arquivo, ou seja, reduza seu tamanho para zero sem removê-lo. Isso permitiria teecontinuar anexando ao arquivo sem precisar reabri-lo.

Truncar um arquivo pode ser feitocomo jlliagre mostrou em sua resposta, ou usando truncate(um utilitário não padrão que faz parte do GNU coreutils):

truncate -s 0 /media/pi/KINGSTON/klima.out

Vero manual paratruncatepara obter mais informações sobre esse utilitário.

Responder2

Se quiser recuperar os blocos de arquivo, você precisa deixar o arquivo em branco, e não desvinculá-lo:

Esta forma portátil deve funcionar com a maioria dos shells:

: > /media/pi/KINGSTON/klima.out

Desvincular o arquivo (ou seja rm, ) remove a entrada do diretório, mas não afeta o conteúdo do arquivo (inode), desde que o arquivo seja mantido aberto por leitores ou gravadores.

Responder3

Você não entende como o sistema está lidando com arquivos.

Você exclui a entrada do arquivo, mas o arquivo ainda existe enquanto o programa mantiver um controle sobre ele. Portanto, tee nunca é notificado de que a entrada foi excluída e ainda grava no arquivo!

Um arquivo exclusivo pode ter muitas entradas graças aos links físicos (criados pelo comando ln).

Você poderia escrever sua própria versão do tee, que fecha e abre o arquivo em cada linha que ele grava no arquivo, mas teria um desempenho muito inferior, pois geraria muitas chamadas de sistema.

Aqui está uma função shell que dividirá sua entrada em vários arquivos:

splitSizeInKio=100

splitInput(){
    local PS4='+splitInput+ '
    set -x
    local i=0
    local fname="$1"
    local ii

    while true
    do if [ $i -lt 10 ]
       then ii=0$i
       else ii=$i
       fi
       local outfile="$fname".$ii
       dd of="$outfile" bs=1024 count=$splitSizeInKio
       i=$((i+1))
    done
}

(Você poderia usar "head" em vez de "dd" se derramasse várias linhas em vez de um tamanho.)

Com o bash, você pode usar "substituição de processo" assim:

prog1 | tee >( splitInput somefilename ) | prog2

informação relacionada