'tail -f' consome a última linha parcialmente, não se importa com novas linhas ou nul

0

Eu tenho um arquivo temporário ( não um fifo / pipe) que precisa ser assistido por vários scripts de leitura. Cada script usa um processo em segundo plano para assistir ao arquivo temporário usando este código:

function file_relay {
    # $1 is a regular file to read from
    local bg_file
    bg_file="$1"

    # $2 is a fifo to relay to
    local outfile
    outfile="$2"

    tail -f "$bg_file" | while read -r line
    do
        [[ ! -z "$line" ]] && { printf "%s" "$line" >>"$outfile"; }
    done
}

Eles precisam ler o arquivo inteiro quando iniciam e, em seguida, procurar por novas linhas, que a função acima faz:

file_relay /tmp/examplefile /tmp/examplefifo &

Cada script irá gerar linhas para este arquivo também. Portanto, é uma situação de vários gravadores e vários leitores.

O problema é que, às vezes, tail -f não espera que uma linha completa esteja disponível, embora eu esteja usando printf para redirecionar para o arquivo e tenho novas linhas no final das sequências. Isso faz com que as linhas lidas sejam corrompidas, com a primeira palavra da última linha sendo acrescentada no final da anterior, então eu recebo:

This is one lineThis

em vez de

This is one line
This is another line

Eu tentei contornar o armazenamento em buffer de printf , o buffer de tail -f , bem como usar sync em torno de gravações no arquivo (o arquivo é somente leitura na função acima e eu não saber como forçar tail a executar sync antes de tentar ler a linha inteira). stdbuf parece não ter nenhum efeito em lugar nenhum, nem usar -z para tail ou terminar strings com $'sync' ou qualquer outra coisa. A única coisa que impede que isso aconteça imediatamente é um único while antes do início do loop tail -f , mas isso não impede que isso aconteça depois disso.

Existe alguma maneira de forçar o %code% a ler somente as linhas completas?

    
por mechalynx 23.03.2017 / 21:41

1 resposta

3

curto: não diretamente

longo: não é portátil (não em POSIX ), mas se você limitar seu interesse para Linux, você pode canalizar a saída de tail -f através de algo que é line-buffered. Por exemplo, como sugerido em comando unix 'tail' lost option '- -line-buffered ' , o GNU grep tem uma opção --line-buffered , permitindo que você faça isso

tail -f "$bg_file" | grep --line-buffered -E '^.*$'

No entanto, como o manual aponta

--line-buffered
Use line buffering, it can be a performance penality.

( FreeBSD tem a mesma opção e comentário de OpenBSD em 2004 , não POSIX ainda ...).

A documentação não aponta isso, mas a O commit inicial em 2001 tinha em mente o tempo gasto fazendo fflush .

    
por 23.03.2017 / 22:21