2012-02-24 124 views
0

我有一个奇怪的问题从STDIN在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我可以在目标文件/tmp/testrsyslogomoutput.txt获得“富”。但是,当我在rsyslog中运行它时,消息似乎只在停止/重新启动rsyslog时发送(我相信某些缓冲区在某个时间点被刷新)。

我首先以为这是Rsyslog的问题。所以我用一个shell替换了我的python程序,而没有改变任何东西到rsyslog配置。 shell脚本的作品完美与rsyslog现在,正如你可以在下面的代码中看到,该脚本真是小巫见大巫:

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

由于我的shell脚本的作品,但我的Python一个没有,我相信我在什么地方犯了一个错误我的Python代码,但我找不到在哪里。如果你能指出我的错误,那将很棒。

感谢提前:)

回答

0

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

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

如果有差别,你也有一个修复:开放,从蟒蛇阅读,而不是sys.stdin的/ dev /标准输入。

编辑:所以cat以某种方式读取任何在标准输入等待并返回,但python块,并等待,直到stdin耗尽。奇怪。您也可以尝试使用单个read()后跟split("\n")替换readlines(),但此时我怀疑这会有所帮助。

因此,忘记诊断并让我们尝试解决办法:强制stdin执行非阻塞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。希望它有效!

+0

我试过你建议它没有任何区别。它仍然适用于这个简单的shell脚本。我也尝试从我的python脚本(没有readlines())中读取/ dev/stdin,它仍然挂起。 – 2012-02-25 04:32:54

+0

哦,好的。下一个想法:通过使用-u标志调用python,将python的I/O缓冲区带出等式。 – alexis 2012-02-25 12:08:39

+0

感谢您的支持亚历克西斯,我也试过用python -u,它没有改变任何东西。 – 2012-02-25 14:39:44

2

readlines不会返回,直到它已完成读取文件。由于管道stdin从未结束,因此readlines也不会完成。停止rsyslog关闭管道并让它结束。

0

如果您使用readline()代替,它将在\n上返回,但这只会写入一行,然后退出。

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

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

我试过了。问题依然存在。我试图循环sys.stdin和/ dev/stdin,并且只有在发送\ n时写入输入。如上所述,使用readline的替代方法也无效。 – 2012-02-25 04:39:26