Смотря что-то записывается в файл с хвостом

У меня есть программа на 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 работает счастливо и с непосредственностью.

С уважением

Другие вопросы по тегам