Evitar buffer de saída para um grupo de comandos (chaves) no script bash

4

Eu tenho um script bash contendo um grupo de comandos em chaves { ... } . Este grupo contém alguns comandos echo iniciais e, em seguida, um loop . Em cada iteração, o loop executa vários comandos slow (basicamente com curl e alguma análise extra). Cada iteração é lenta (por causa da interação da rede), mas imprime uma linha (de código python); Até onde eu posso ver, não deve haver nenhum problema de buffer vindo dos próprios comandos porque eles terminam seu trabalho e saem.

Todo o grupo de comandos é canalizado para python -u (eu também tentei com tail -f para verificar) e obviamente todo o loop é executado antes que algo seja lido por python -u ou tail -f .

Eu sei como descomprimir (quando possível) um comando com várias ferramentas como stdbuf , mas não acho que possa ajudar aqui porque parece que o problema vem do agrupamento de comandos em vez de tal ou tal comando.

Alguma dica?

    
por Thomas Baruchel 28.11.2015 / 16:20

2 respostas

4

(Nota para os futuros leitores: o tom de exasperação aqui não é para a questão, mas para os erros que cometi tentando respondê-lo e as múltiplas edições que eles implicaram.)

Oh, pelo amor de Deus. O problema está em tail -f . Isso funciona muito bem:

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
        sleep 0.5
        /bin/echo $i
    done;
} | cat
printf 'bye\n'

Não é o cachimbo, não é o grupo. É tail . Como em perseguir nossas próprias caudas!

Portanto, tail -f falhou porque não sai imediatamente por algum motivo. Não tenho certeza porque python -u está falhando, mas não acho que seja algo no script. Talvez tente unbuffer com isso. Tente o seu script com cat , pelo menos, e verifique se ele está sem buffer nesse caso.

Tentativa anterior falhada intencionalmente deixada aqui para que futuros leitores possam entender os comentários.

Este script exibe o mesmo tipo de problema de buffer que você está recebendo:

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
    sleep 0.5
    printf '%s\n' $i
    done;
} | tail -f
printf 'bye\n'

Este não é. A saída dentro do grupo é redirecionada para stderr, depois stderr do grupo inteiro é canalizado para o comando. Desde que é stderr, é unbuffered.

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
    sleep 0.5
    printf '%s\n' $i 1>&2
    done;
} |& tail -f
printf 'bye\n'

Adaptado da resposta de Wang HongQin em esta questão . A dificuldade estava em encontrar uma maneira de desabafar o tubo com chaves, em vez de um comando explícito. Tive que mexer um pouco para fazer o redirecionamento funcionar corretamente.

    
por 28.11.2015 / 17:10
1

você só precisa fazer:

{   stdbuf -o0 curl ...
    stdbuf -o0 whatever ...
}|  tail -f

... que funcionará para aplicativos dinamicamente vinculados, embora eu tenha certeza que curl inclui seu próprio unbuffer de algum tipo.

    
por 28.11.2015 / 20:57