Смотря что-то записывается в файл с хвостом
У меня есть программа на Python, которая медленно генерирует какой-то вывод.
Я хочу записать это в файл, но я также подумал, что смогу посмотреть его вживую с хвостом.
Итак, в одном терминале я делаю:
python myprog.py > output.txt
и в другом терминале:
tail -f output.txt
Но кажется, что хвост не показывает мне ничего, пока работает программа на Python.
Если я нажму Ctrl-C, чтобы убить скрипт Python, вдруг хвост output.txt
начинает заполняться. Но не во время работы питона.
Что я делаю неправильно?
5 ответов
Вам также может понадобиться явно очистить буфер для его передачи по генерации. Это связано с тем, что выходные данные обычно печатаются только тогда, когда буфер канала заполняется (это в килобайтах, как я полагаю), и когда сообщение stdin заканчивается. Это, вероятно, сэкономить на чтении / записи. Вы можете сделать это после каждой печати или, если вы делаете цикл, после последней печати в цикле.
import sys
...
print('Some message')
sys.stdout.flush()
Запустите python с флагом небуферизованного:
python -u myprog.py > output.txt
Выходные данные будут распечатаны в режиме реального времени.
Вместо того, чтобы пытаться подключить живой файл, используйте tee
вместо. Это было сделано, чтобы сделать именно то, что вы пытаетесь сделать.
От человека тройник:
tee (1) - справочная страница по Linux
Имя tee - чтение из стандартного ввода и запись в стандартный вывод и файлы
конспект
tee [OPTION]... [FILE]...
Описание
Скопируйте стандартный ввод в каждый ФАЙЛ, а также в стандартный вывод.
-a, --append append to the given FILEs, do not overwrite -i, --ignore-interrupts ignore interrupt signals --help display this help and exit --version output version information and exit
Если ФАЙЛ - -, скопируйте снова в стандартный вывод.
Так что в вашем случае вы бы запустили:
python myprog.py | tee output.txt
РЕДАКТИРОВАТЬ: Как уже отмечали другие, этот ответ будет сталкиваться с той же проблемой, которую первоначально имел OP, если sys.stdout.flush()
используется в программе python, как описано в принятом ответе Дэйви. Тестирование, которое я провел перед публикацией этого ответа, не точно отражало сценарий использования OP.
tee
все еще может использоваться в качестве альтернативного, хотя и не оптимального, метода отображения выходных данных при записи в файл, но ответ Дейви, безусловно, является правильным и лучшим ответом.
Терминология: в этом сценарии нигде нет трубы. (Я отредактировал вопрос, чтобы это исправить). Каналы - это другой тип файла (буфер внутри ядра).
Это редирект на обычный файл.
C stdio и Python, по умолчанию, делают stdout буферизованной строкой, когда она подключена к TTY, в противном случае она является полной буферизацией. Строковый буфер означает, что буфер сбрасывается после новой строки. Полный буферизированный означает, что он только сбрасывается, чтобы стать видимым для ОС (т.е. с write()
системный вызов), когда он полон.
Вы увидите результат в конце концов, кусками по 4 Кбайт за раз. (Я не знаю размер буфера по умолчанию.) Как правило, это более эффективно и означает меньше записей на ваш реальный диск. Но не подходит для интерактивного мониторинга, потому что вывод скрыт в памяти процесса записи, пока он не будет очищен.
В переполнении стека есть Отключить буферизацию вывода Python Q&A, в которой перечислено много способов получить небуферизованный (или буферизованный?) Вывод на стандартный вывод в Python. Сам вопрос суммирует ответы.
Варианты включают бег python -u
(Или я полагаю #!/usr/bin/python -u
в верхней части вашего сценария), или используя PYTHONUNBUFFERED
переменная окружения для этой программы. Или явная очистка после некоторых / всех print
функции, как подсказывает ответ @Davey.
Некоторые другие программы имеют аналогичные параметры, например, GNU grep имеет --line-buffered
и GNU sed
имеет -u
/ --unbuffered
для таких случаев использования, как этот, или, например, для вывода результатов вашей программы на Python. например ./slowly-output-stuff | grep --line-buffered 'foo.*bar'
,
Когда я использую tail, он почти всегда отслеживает файл журнала, например, сообщения электронной почты.
Это может быть немного нестандартно, но вместо использования print
/print()
/write()
в вашем коде Python, почему бы не использовать модуль регистрации? (из PSL) Обратите внимание, что форматер журналирования может быть сконфигурирован НЕ для вывода всех этих временных и идентификационных кодов, связанных с традиционным журналом.
Выходные данные могут быть сконфигурированы для перехода к файлу (данных), и, поскольку нет задержки или перенаправления буферизации, tail работает счастливо и с непосредственностью.
С уважением