tee -a não recria o arquivo

6

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

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; no entanto, quando eu excluir (manualmente ou por CRON) o arquivo klima.out , ele não é recriado. O comando continua em execução, o arquivo de log continua a ser anexado, mas o arquivo klima.out não retorna. (também sem buffer). Eu quero apagá-lo uma vez por semana para não deixá-lo crescer em todos os limites. Alguma sugestão?

    
por hans 29.05.2017 / 16:09

3 respostas

13

Se você deseja recuperar os blocos de arquivos, é necessário que o arquivo seja excluído, sem desvinculá-lo:

Este modo portátil deve funcionar com a maioria dos shells:

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

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

    
por 29.05.2017 / 16:25
19

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

Quando você exclui o arquivo, o processo tee 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 arquivos abertos que fazem referência ao arquivo sejam fechados.

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

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

Para evitar ter que reiniciar o pipeline, você pode escolher truncar o arquivo, ou seja, reduzir seu tamanho a zero sem removê-lo. Isso permitiria que tee continuasse anexando ao arquivo sem precisar reabri-lo.

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

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

Consulte o manual para truncate para mais informações sobre esse utilitário .

    
por 29.05.2017 / 16:25
4

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

Você exclui a entrada do arquivo, mas o arquivo ainda existe contanto que o programa mantenha um controle sobre ele. Então, o tee nunca é notificado, a entrada foi excluída e ainda é gravada no arquivo!

Um arquivo único pode ter muitas entradas graças aos hard links (criados pelo comando ln).

Você pode escrever sua própria versão do tee, que fecha e abre o arquivo em cada linha que ele grava no arquivo, mas seria muito fraco, já que geraria muitas chamadas do sistema.

Aqui está uma função shell que irá 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ê pode usar "head" em vez de "dd" se você derramar em um número de linhas em vez de um tamanho.)

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

prog1 | tee >( splitInput somefilename ) | prog2
    
por 29.05.2017 / 16:50

Tags