Ao tentar gravar o stdout de um script Python em um arquivo de texto ( python script.py > log
), o arquivo de texto é criado quando o comando é iniciado, mas o conteúdo real não é gravado até que o script Python seja concluído. Por exemplo:
script.py:
import time
for i in range(10):
print('bla')
time.sleep(5)
imprime no stdout a cada 5 segundos quando chamado python script.py
, mas quando eu ligo python script.py > log
, o tamanho do arquivo de log permanece zero até o script terminar. É possível gravar diretamente no arquivo de log, de forma que você possa acompanhar o progresso do script (por exemplo, usando tail
)?
EDIT Acontece que python -u script.py
faz o truque, eu não sabia sobre o buffer do stdout.
Respostas:
Isso está acontecendo porque, normalmente, quando o processo STDOUT é redirecionado para algo diferente de um terminal, a saída é armazenada em buffer em algum buffer de tamanho específico do SO (talvez 4k ou 8k em muitos casos). Por outro lado, ao enviar para um terminal, o STDOUT terá buffer de linha ou nenhum buffer; portanto, você verá a saída após cada
\n
ou para cada caractere.Geralmente, você pode alterar o buffer STDOUT com o
stdbuf
utilitário:Agora, se você
tail -F log
, você deve ver cada linha de saída imediatamente à medida que é gerada.Como alternativa, a descarga explícita do fluxo de saída após cada impressão deve obter o mesmo. Parece que
sys.stdout.flush()
deve conseguir isso em Python. Se você estiver usando Python 3.3 ou mais recente, aprint
função também tem umaflush
palavra-chave que faz isso:print('hello', flush=True)
.fonte
python -u script.py
faz o truque. EDITAR Tantas respostas de uma só vez, eu aceitei a sua, uma vez que ela me apontava na direção do buffer.--line-buffered
paragrep
, mas outros não.stdbuf
é o utilitário geral para lidar com aqueles que não o fazem.stdbuf -o0 python script.py > log
, neste tipo de circunstâncias determinadas?-oL
é um compromisso. Em geral, buffers maiores fornecerão melhor desempenho ao redirecionar para algum lugar (menos chamadas do sistema e menos operações de E / S). No entanto, se for absolutamente necessário ver cada caractere conforme é produzido, sim,-o0
seria necessário.Isso deve fazer o trabalho:
Como Python armazenará o buffer
stdout
por padrão, aqui eu useisys.stdout.flush()
para liberar o buffer.Outra solução seria usar a opção
-u
(sem buffer) depython
. Portanto, o seguinte também será feito:fonte
A variação no tema de usar a própria opção do python para saída sem buffer seria usar
#!/usr/bin/python -u
como primeira linha.Como
#!/usr/bin/env python
esse argumento extra não funcionará, então, como alternativa, é possível executáPYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt
-lo ou executá -lo em duas etapas:fonte
Você deve passar
flush=True
para aprint
função:De acordo com a documentação, por padrão,
print
não impõe nada sobre a liberação:E a documentação para
sys
strems diz:Se você está preso a uma versão antiga do python, deve chamar o
flush
método dosys.stdout
fluxo:fonte
DigitalTrauma
disse 10 horas antes. Você deve votar novamente na publicação dele, e não publicar a mesma coisa novamente.print(flush=True)
foi adicionada a essa resposta após a minha por um autor de terceiros. Acho que é de mau gosto extrair conteúdos da minha resposta para colocá-los em outro sem crédito. Decidi adicionar minha resposta apenas porque nenhuma resposta mencionava a maneira mais simples de alcançar o que o OP queria nas versões mais recentes do python, e adicionei a "maneira antiga" apenas por completude. Na próxima vez, verifique o histórico de revisões antes de comentar e / ou fazer voto negativo.__future__
importação:from __future__ import print_function
. Mas sim, isso é apenas para compatibilidade com Python 3 #