2017-08-30 100 views
3

我想通過發送一系列命令並捕獲輸出來測試特定的聊天程序。在Python中一次讀取stdin行

如何傳遞:

sleep 2 
echo test 
sleep 2 
echo test1 

我已經試過這樣:

(sleep 2; echo test; sleep 2; echo test1) | python3 test.py 

,但它只是打印第一部分,而第二個我什麼也沒得到。它進入了一個無限循環。

Python程序的代碼是:

import sys, select 

while True: 
    socket_list = [sys.stdin] 
    read_sockets, write_sockets, error_sockets = select.select(socket_list, [], []) 
    for sock in read_sockets: 
    message = sys.stdin.readline() 
    sys.stdout.write("> %s: ") 
    sys.stdout.flush() 

我應該提到這是不完整的程序,但它是它有助於重建完全相同的效果的部分。

+0

瞎猜,但什麼'{睡眠2;回聲測試;睡2;回聲test1}'也許重定向到python而不是管道? –

+0

'date +%s; (睡眠2;回聲測試;睡眠2;回聲測試1)| perl -pe'$ _ = time()。「」。$ _''同時顯示'test'字符串和兩秒延遲。 – thrig

+1

你需要告訴我們你是如何發送和接收。這聽起來像是一個問題,但很難說。 –

回答

2

您的示例轉至循環,因爲在echo test1stdin已關閉且read()始終返回空。 此外,您不應該使用select另一個阻止呼叫。如果您想 將其用於多個對象,則仍可能被前一事件的readline 阻止。

對於從stdin時間讀取一條線,你不需要使用 select.select()。可能最簡單的方法來實現這一目標:

for line in sys.stdin: 
    print(line) 

如果你想爲使用stdin或作爲參數傳遞給 程序文件的列表,Python的 fileinput模塊 是開箱即用的解決方案。

如果你想/需要使用反正select.select()

import os, sys, select 

buffer = "" 
while True: 
    select.select([sys.stdin.fileno()], [], []) 
    read = os.read(sys.stdin.fileno(), 512) 

    # empty read: EOF 
    if len(read) == 0: 
    # buffer might not be empty 
    if len(buffer) > 0: 
     sys.stdout.write(buffer + "\n") 

    break 

    # find newlines 
    parts = read.split("\n") 
    buffer += parts.pop(0) 

    while len(parts) > 0: 
    sys.stdout.write(buffer + "\n") 
    buffer = parts.pop(0) 

當一個對象準備好, select.select 疏導。在這種情況下唯一的對象是stdin。對於多個 對象,您需要檢查返回值select.select以找出 哪一個已準備就緒。 os.read()用於做非阻塞讀取 stdin(或者: 可以使用stdin.read(1)一次讀取一個字符)。 read.split("\n")用於查找換行符,請注意它是 單個讀取可能會產生多行。

+0

優秀的迴應,並感謝您使用select.select發送示例。事實上,在最後一個回聲之後,有多個b'發送到stdin,因此檢查是否有空的讀取並退出來解決問題。 – Michael

0

cat運行strace之後,我創造了這個:

import sys 

while True: 
    data = sys.stdin.read() 
    if not len(data): 
     break 
    sys.stdout.write(data) 

命令

(sleep 2; echo test; sleep 2; echo test1) | python3 test.py 

輸出

test 
test1 

這解決方案依賴於這個事實:

如果已到達文件的末尾,f.read()將返回一個空字符串('')。

請參閱Methods of File Objects

如果需要使用select版本:

import os 
import select 
import sys 

while True: 
    rlist = [sys.stdin.fileno()] 
    wlist = [] 
    xlist = [] 
    rlist, wlist, xlist = select.select(rlist, wlist, xlist) 
    if sys.stdin.fileno() in rlist: 
     data = os.read(sys.stdin.fileno(), 4096) 
     if not len(data): 
      break 
     sys.stdout.write(data)