Eu tenho um programa python que está, lentamente, gerando alguma saída.
Quero capturar isso em um arquivo, mas também pensei que poderia assistir ao vivo com o tail.
Então, em um terminal, estou fazendo:
python myprog.py > output.txt
e em outro terminal:
tail -f output.txt
Mas parece que a cauda não está me mostrando nada enquanto o programa python está em execução.
Se eu apertar ctrl-c para matar o script python, de repente a cauda output.txt
começa a encher. Mas não enquanto o python está em execução.
O que estou fazendo errado?
Você também pode precisar liberar explicitamente o buffer para que ele seja canalizado na geração. Isso ocorre porque a saída normalmente é impressa apenas quando o buffer do canal é preenchido (que é em kilobytes, acredito) e quando a mensagem stdin termina. Isso provavelmente é para economizar em leitura/gravação. Você pode fazer isso após cada impressão ou, se estiver em loop, após a última impressão dentro do loop.
Execute o python com o sinalizador sem buffer:
A saída será impressa em tempo real.
Em vez de tentar acompanhar um arquivo ativo, use
tee
. Foi feito para fazer exatamente o que você está tentando fazer.Da camiseta masculina :
Então, no seu caso, você executaria:
EDIT: Como outros apontaram, esta resposta terá o mesmo problema que o OP estava tendo originalmente, a menos que
sys.stdout.flush()
seja usado no programa python, conforme descrito na resposta aceita de Davey. O teste que fiz antes de postar esta resposta não refletiu com precisão o caso de uso do OP.tee
ainda pode ser usado como um método alternativo - embora menos do que ideal - de exibir a saída enquanto também grava no arquivo, mas a resposta de Davey é claramente a resposta correta e melhor.Terminologia: Não há tubulação em nenhum lugar neste cenário. (Eu editei a pergunta para corrigir isso). Pipes são um tipo diferente de arquivo (um buffer dentro do kernel).
Este é um redirecionamento para um arquivo normal.
C stdio e Python, por padrão, tornam o buffer de linha stdout quando conectado a um TTY, caso contrário, é buffer completo. Buffer de linha significa que o buffer é liberado após uma nova linha. Full-buffered significa que ele só é liberado para se tornar visível para o sistema operacional (ou seja, com uma
write()
chamada do sistema) quando está cheio.Você verá a saída eventualmente, em pedaços de talvez 4 KiB por vez. (Não sei o tamanho do buffer padrão.) Isso geralmente é mais eficiente e significa menos gravações em seu disco real. Mas não é ótimo para monitoramento interativo, porque a saída fica oculta dentro da memória do processo de gravação até que seja liberada.
Em Stack Overflow, há uma sessão de perguntas e respostas sobre Disable output buffering Python, que lista muitas maneiras de obter uma saída sem buffer (ou com buffer de linha?) para stdout em Python. A própria pergunta resume as respostas.
As opções incluem executar
python -u
(ou acho que colocar#!/usr/bin/python -u
no topo do seu script) ou usar aPYTHONUNBUFFERED
variável de ambiente para esse programa. Ou descarga explícita após algumas/todas asprint
funções, como sugere a resposta de @Davey.Alguns outros programas têm opções semelhantes, por exemplo, GNU grep tem
--line-buffered
, e GNUsed
tem-u
/--unbuffered
, para casos de uso como este ou, por exemplo, canalizando a saída do seu programa python. ex./slowly-output-stuff | grep --line-buffered 'foo.*bar'
.Quando eu uso o tail, ele quase sempre rastreia um arquivo de log, por exemplo, mensagens (email).
Isso pode ser um pouco fora do comum, mas em vez de usar
print
/print()
/write()
em seu código Python, por que não usar o módulo de registro? (do PSL) NB, um formatador de registro pode ser configurado para NÃO gerar todos os códigos de ID e tempo associados a um registro tradicional.A saída pode ser configurada para ir para um arquivo (dados) e, como não há atraso de buffer ou redirecionamento, o tail funciona de maneira feliz e imediata.
Cumprimentos