2017-03-02 68 views
2

標準輸出。如果需要定期檢查正在運行的進程的stdout。例如,該進程是tail -f /tmp/file,它是在python腳本中產生的。然後,每個x秒,該子進程的stdout被寫入一個字符串並進一步處理。子進程最終由腳本停止。檢查正在運行的子進程的蟒蛇

解析子進程的標準輸出,如果直到現在使用check_output,這似乎不起作用,因爲進程仍在運行並且不會產生明確的輸出。

>>> from subprocess import check_output 
>>> out = check_output(["tail", "-f", "/tmp/file"]) 
#(waiting for tail to finish) 

應該可以使用線程的子過程,使得多個子過程的輸出可被處理(例如,尾-f/TMP/file1的,尾-f/TMP/file2的)。

我如何開始一個子進程,定期檢查和處理標準輸出,並最終停在一個多線程友好的方式子? python腳本在Linux系統上運行。

的目標不是連續地讀取文件,尾部命令是一個例子,因爲它的表現完全一樣使用的實際命令。

編輯:我沒有想到這一點,該文件不存在。 check_output現在只是等待過程完成。

edit2:另一種方法,PopenPIPE似乎導致同樣的問題。它等待tail完成。

>>> from subprocess import Popen, PIPE, STDOUT 
>>> cmd = 'tail -f /tmp/file' 
>>> p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) 
>>> output = p.stdout.read() 
#(waiting for tail to finish) 
+0

http://stackoverflow.com/a/6482200/1866177可能解決了這個問題。 – Dschoni

+1

您的示例比無法讀取標準輸出有更大的問題。請修復它。 –

+0

@Dschoni,OP正在嘗試攝取,而不是重定向輸出。這使得它比您提供的鏈接更完整。 –

回答

4

你的第二次嘗試是90%正確的。唯一的問題是,一旦它完成,你試圖在同一時間讀取所有tail的標準輸出。然而,tail旨在在後臺運行(無限期?),讓你真正想讀的標準輸出從中行由行:

from subprocess import Popen, PIPE, STDOUT 
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 
for line in p.stdout: 
    print(line) 

我已刪除了shell=Trueclose_fds=True參數。第一個是不必要的並且有潛在危險,而第二個只是默認設置。

記住,文件對象是可迭代對他們在Python線。該for迴路將運行直到tail模具,但因爲它出現它將處理每一行,相對於read,這將阻塞,直到tail模具。

如果我創建/tmp/file一個空文件,啓動該程序,並使用另一個shell,程序會呼應線開始呼應線到文件中。你應該用更有用的東西代替print

這裏是我開始上面的代碼後輸入的命令的一個例子:

命令行

$ echo a > /tmp/file 
$ echo b > /tmp/file 
$ echo c >> /tmp/file 

程序輸出(通過Python在不同的外殼)

b'a\n' 
b'tail: /tmp/file: file truncated\n' 
b'b\n' 
b'c\n' 

如果你希望你的主程序能夠響應你的資源池到tail的輸出,在單獨的線程中啓動循環。你應該讓這個線程成爲一個守護進程,這樣它不會阻止你的程序退出,即使tail沒有完成。您可以讓線程打開子進程,也可以將標準輸出傳遞給它。我更喜歡後者的方法,因爲它給你更多的控制在主線程:

def deal_with_stdout(): 
    for line in p.stdout: 
     print(line) 

from subprocess import Popen, PIPE, STDOUT 
from threading import Thread 
p = Popen(["tail", "-f", "/tmp/file"], stdin=PIPE, stdout=PIPE, stderr=STDOUT) 
t = Thread(target=deal_with_stdout, daemon=True) 
t.start() 
t.join() 

這裏的代碼幾乎相同,增加一個新的線程。我在最後添加了一個join(),所以程序會表現得很好(join在返回之前等待線程死亡)。您可能想用您通常運行的任何處理代碼替換它。

如果您的線程足夠複雜,您可能還想繼承Thread並覆蓋run方法,而不是傳入簡單的target

+0

謝謝你的詳細解釋,這可以幫助我很多! –

+1

我很高興它做到了。一旦你知道如何使用它,多線程和多處理是一個相當簡單的工具,但很難進入。對我來說最糟糕的部分是術語。 –