При попытке записать стандартный вывод из скрипта Python в текстовый файл ( python script.py > log
) текстовый файл создается при запуске команды, но фактическое содержимое не записывается до тех пор, пока скрипт Python не завершится. Например:
script.py:
import time
for i in range(10):
print('bla')
time.sleep(5)
выводит на стандартный вывод каждые 5 секунд при вызове с помощью python script.py
, но когда я вызываю python script.py > log
, размер файла журнала остается нулевым, пока сценарий не завершится. Можно ли напрямую записывать в файл журнала, чтобы вы могли следить за ходом сценария (например, используя tail
)?
РЕДАКТИРОВАТЬ Оказывается, что python -u script.py
делает трюк, я не знал о буферизации стандартного вывода.
Ответы:
Это происходит потому, что обычно, когда процесс STDOUT перенаправляется не на терминал, а в выходной файл, он буферизируется в некотором буфере определенного размера ОС (во многих случаях, возможно, 4 или 8 КБ). И наоборот, при выводе на терминал STDOUT будет буферизован строкой или не буферизован вообще, поэтому вы увидите вывод после каждого
\n
или для каждого символа.Обычно вы можете изменить буферизацию STDOUT с помощью
stdbuf
утилиты:Теперь, если вы
tail -F log
, вы должны увидеть каждую строку вывода сразу же, как он генерируется.Альтернативно явная очистка выходного потока после каждого отпечатка должна достигать того же самого. Похоже,
sys.stdout.flush()
следует достичь этого в Python. Если вы используете Python 3.3 или более позднюю версию, тоprint
функция также имеетflush
ключевое слово , которое делает это:print('hello', flush=True)
.источник
python -u script.py
делает свое дело. РЕДАКТИРОВАТЬ Так много ответов сразу, я принял ваш, так как он указал мне в направлении буферизации.--line-buffered
дляgrep
, но некоторые другие нет.stdbuf
это общая утилита для борьбы с теми, кто этого не делает.stdbuf -o0 python script.py > log
в таких обстоятельствах?-oL
- это компромисс. Как правило, большие буферы обеспечивают лучшую производительность при перенаправлении куда-либо (меньше системных вызовов и меньше операций ввода-вывода). Однако если абсолютно необходимо видеть каждый символ как выводимый, тогда да,-o0
потребуется.Это должно сделать работу:
Поскольку Python будет буферизовать
stdout
по умолчанию, здесь я использовалsys.stdout.flush()
для очистки буфера.Другое решение было бы использовать
-u
(небуферизованный) переключательpython
. Итак, следующее тоже подойдет:источник
Вариация на тему использования собственной опции python для небуферизованного вывода будет заключаться в использовании в
#!/usr/bin/python -u
качестве первой строки.С
#!/usr/bin/env python
этим дополнительным аргументом не сработает, так что в качестве альтернативы можно запуститьPYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt
или сделать это в два этапа:источник
Вам следует перейти
flush=True
кprint
функции:Согласно документации, по умолчанию
print
ничего не предписывает очистка:И документация для
sys
России гласит:Если вы застряли в древней версии Python, вам нужно вызвать
flush
методsys.stdout
потока:источник
DigitalTrauma
сказано за 10 часов до этого. Вы должны проголосовать за его пост, а не публиковать то же самое снова.print(flush=True)
была добавлена к этому ответу после моего от стороннего автора. Я считаю плохим вкусом вырывать содержимое из моего ответа, вставляя его в другой без кредита. Я решил добавить свой ответ исключительно потому, что ни в одном ответе не было упоминания о самом простом способе достижения того, что OP хотел получить в более новых версиях python, и я добавил «старый способ» только для полноты. В следующий раз, пожалуйста, проверьте историю изменений, прежде чем комментировать и / или понизить.__future__
импорт:from __future__ import print_function
. Но да, это только для совместимости с Python 3