0

我有一个奇怪的问题要在 python 脚本中从 STDIN 读取。

这是我的用例。我为 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 的问题。所以我用一个 shell 替换了我的 python 程序,没有改变任何 rsyslog 配置。shell 脚本与 rsyslog 完美配合,正如您在下面的代码中所见,该脚本非常简单:

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

由于我的 shell 脚本有效,但我的 Python 脚本无效,我相信我在 Python 代码的某个地方犯了一个错误,但我找不到在哪里。如果你能指出我的错误,那就太好了。

提前致谢 :)

4

3 回答 3

3

readlines在完成读取文件之前不会返回。由于输送标准输入的管道永远不会完成,因此readlines也永远不会完成。停止 rsyslog 会关闭管道并让它完成。

于 2012-02-24T21:24:08.823 回答
0

如果您改用readline()它,它将返回 on \n,尽管这只会写一行然后退出。

如果你想继续写行,只要它们在那里,你可以使用一个简单的for

for line in fd:
  fd.write("Receiving log message : \n%s\n" % (line)
fd.close()
于 2012-02-24T22:06:23.943 回答
0

我还怀疑原因是 rsyslog 没有终止。readlines()在达到真正的 EOF 之前不应返回。但是为什么 shell 脚本会有不同的行为呢?也许使用 /dev/stdin 是原因。试试这个版本,看看它是否仍然可以运行而不挂起:

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

如果这有所不同,您还将有一个修复:从 python 打开并读取 /dev/stdin,而不是 sys.stdin。

编辑:所以cat以某种方式读取在 stdin 处等待的任何内容并返回,但 python 阻塞并等待直到 stdin 用尽。奇怪的。您也可以尝试用readlines()一个read()后跟替换split("\n"),但在这一点上我怀疑这会有所帮助。

所以,忘记诊断,让我们尝试一种解决方法:强制标准输入执行非阻塞 i/o。以下应该做到这一点:

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. 希望它有效!

于 2012-02-24T23:22:34.253 回答