не могу правильно читать из STDIN - PullRequest
0 голосов
/ 25 февраля 2012

У меня странная проблема при чтении из STDIN в скрипте Python.

Вот мой пример использования.У меня rsyslog, настроенный с модулем вывода, поэтому rsyslog может передавать сообщения журнала в мой скрипт Python.

Мой скрипт Python действительно тривиален:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys

fd = open('/tmp/testrsyslogomoutput.txt', 'a')
fd.write("Receiving log message : \n%s\n" % ('-'.join(sys.stdin.readlines())))
fd.close()

Если я запускаю echo "foo" | mypythonscript.py, я могу получить"foo" в целевом файле /tmp/testrsyslogomoutput.txt.Однако, когда я запускаю его в rsyslog, кажется, что сообщения отправляются только тогда, когда я останавливаю / перезапускаю rsyslog (я думаю, что какой-то буфер очищается в какой-то момент).

Сначала я подумал, что это проблема с Rsyslog.Поэтому я заменил свою программу на Python на оболочку, не меняя ничего в конфигурации rsyslog.Сценарий оболочки прекрасно работает с rsyslog, и, как вы можете видеть из приведенного ниже кода, сценарий действительно тривиален:

#! /bin/sh
cat /dev/stdin >> /tmp/testrsyslogomoutput.txt

Поскольку мой сценарий оболочки работает, а мой Python - нет, я считаю, что допустил ошибкугде-то в моем коде Python, но я не могу найти где.Если бы вы могли указать мне на мою ошибку (ошибки), это было бы замечательно.

Заранее спасибо:)

Ответы [ 3 ]

2 голосов
/ 25 февраля 2012

readlines не вернется, пока не завершит чтение файла. Поскольку стандартный ввод в трубу никогда не заканчивается, readlines также никогда не заканчивается. Остановка rsyslog закрывает канал и позволяет ему закончить.

0 голосов
/ 25 февраля 2012

Я также подозреваю, что причина в том, что rsyslog не завершается. readlines() не должен возвращаться, пока не достигнет реального EOF. Но почему сценарий оболочки действует иначе? Возможно, использование / dev / stdin является причиной. Попробуйте эту версию и посмотрите, работает ли она без зависаний:

#!/bin/sh
cat >> /tmp/testrsyslogomoutput.txt

Если это что-то изменит, у вас также будет исправление: откройте и читайте / dev / stdin из python вместо sys.stdin.

Редактировать: Итак, cat каким-то образом читает все, что ожидает в stdin, и возвращает, но python блокирует и ждет, пока stdin не будет исчерпан. Странный. Вы также можете попробовать заменить readlines() на один read() с последующим split("\n"), но на данный момент я сомневаюсь, что это поможет.

Итак, забудьте о диагнозе и давайте попробуем обойти эту проблему: заставить стандартный ввод ввода-вывода неблокировать. Следующее должно сделать это:

import fcntl, os

# Add O_NONBLOCK to the stdin descriptor flags 
flags = fcntl.fcntl(0, fcntl.F_GETFL)
fcntl.fcntl(0, fcntl.F_SETFL, fl | os.O_NONBLOCK)

message = sys.stdin.read().split("\n")  # Read what's waiting, in one go
fd = open('/tmp/testrsyslogomoutput.txt', 'a')
fd.write("Receiving log message : \n%s\n" % ('-'.join(message)))
fd.close()

Вы, вероятно, хотите использовать это в сочетании с python -u. Надеюсь, что это работает!

0 голосов
/ 25 февраля 2012

Если вы используете readline() вместо этого, он вернется к \n, хотя при этом будет записана только одна строка, а затем завершено.

Если вы хотите продолжать писать строки, пока они там есть, вы можетеиспользуйте простое for:

for line in fd:
  fd.write("Receiving log message : \n%s\n" % (line)
fd.close()
...