2012-02-24 155 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