2014-10-06 46 views
0

我試圖構建一個python腳本,它在10秒內打開一個子進程(bash腳本)並將「stdout」讀入變量。 10秒後,我需要通過POST請求將數據傳輸到服務器。 如何使POST請求我知道,但如何在10秒內收集「標準輸出」?使用Popen從Python的「標準輸出」部分讀取

我發現了很多例子,如何使用「Popen」,啓動bash腳本並立即讀取stderr而不會發生biffering,但是如何在一段時間內收集輸出並且部分發布?

+0

你能提供的一些代碼你一直在嘗試什麼?所以我們可以更好地理解,並用它作爲答案的基礎。 – jdehesa 2014-10-06 08:09:46

回答

0

我覺得這個解決方案有兩個簡單的責任線程,乾淨而優雅。

import os 
import subprocess 
import threading 
import functools 

from time import sleep 

class OutputMonitor(threading.Thread): 

    """ Start the subprocess in separate thread and append it's output to a buffer. """ 

    def __init__(self, cmd): 
     super(OutputMonitor, self).__init__() 
     self.daemon = True 
     self.cmd = cmd 
     self.buffer = '' 
     self.buflock = threading.Lock() 

    def run(self): 

     popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

     while popen.poll() is None: 
      data = popen.stdout.read(4) 
      if data != "": 
       with self.buflock: 
        self.buffer += data 

    def get_current_output(self): 
     with self.buflock: 
      buf = self.buffer 
      self.buffer = "" 
      return buf 

class OutputHandler(threading.Thread): 

    """ 
     Start a thread responsible for tracking subprocess output, and periodically 
     check if it has produced new output. If so, call handler to process this data. 
    """ 

    def __init__(self, cmd, interval, filepath): 
     super(OutputHandler, self).__init__() 
     self.om = OutputMonitor(cmd) 
     self.interval = interval 

     # Replace it with your handler init... 
     self.filepath = filepath 
     if os.path.exists(self.filepath): 
      os.unlink(self.filepath) 

    def run(self): 

     self.om.start() 
     while self.om.is_alive(): 
      sleep(self.interval) 
      data = self.om.get_current_output() 

      self._handle_data_chunk(data) 

    def _handle_data_chunk(self, data): 

     # Replace it with you handling. 
     with open(self.filepath, 'a') as f: 
      f.write(data) 


if __name__ == '__main__': 

    logfile_path = "C:\\log.txt" 

    interval = 5 
    cmd = ['ping', 'n', '10', '127.0.0.1'] 

    oh = OutputHandler(cmd, interval, logfile_path) 
    oh.start() 
    oh.join() 
+0

的即時消息感謝您的幫助!但似乎在第一次輸出後,過程掛起....我只看到5秒後的第一個輸出,然後沒有任何事情發生...... – vyazikov 2014-10-06 09:52:45

+0

'cmd'我放入這個例子永遠運行,所以它確實掛起了,你應該把它替換成你的bash腳本的路徑,然後在'subprocess.Popen'中加入'shell = True'呼叫,另外,'timeout'設置爲臨時的,因此將其替換爲期望的值 我已經更改了代碼以符合您的要求,請再試一次 – mrad 2014-10-06 09:56:32

+0

yeap我瞭解超時,測試5秒很好)感謝代碼,我用簡單的'cmd ='ping google.com''再次嘗試了它,並且它再次掛起...我只看到第一個輸出像以前一樣......另外我也嘗試使用我的腳本..我啓動FFMPEG'ffmpeg -i .....- loglevel verbose .......',我立即看到輸出。 !))) – vyazikov 2014-10-06 10:05:32

0

你可以做類似下面是什麼東西:

  1. 點子進程輸出到控制檯輸出
  2. 捕獲的變量,它是常見的發佈和捕捉功能
  3. 設置輸出的線程發佈日誌每10秒

進口線程,SYS,子

out = "" 
def postLogs(): 
    print out 
    #do your posting here 
    threading.Timer(10.0, postLogs).start() #execute this function every 10 seconds 

proc = subprocess.Popen("ping google.com", shell=True,stdout=subprocess.PIPE,  stderr=subprocess.STDOUT) 
while proc.poll() is None: 
    out = proc.stdout.readline() 
    sys.stdout.flush 
    if out != "": 
     postLogs() 
+0

感謝您的支持..但似乎它不工作(我使用Linux)我試過'subprocess.Popen(「ping谷歌。 com「'和我立即看到輸出.. – vyazikov 2014-10-06 09:33:31

+0

我編輯了我的解決方案,我有C:\作爲當前的工作目錄,這是失敗的原因UNIX。 – user3 2014-10-06 10:46:01

+0

嘗試過,nope(不工作......我看到來自PING命令 – vyazikov 2014-10-06 11:40:14

0

好讓繼續毫弧度的腳本 我編輯它只是一點點。增加了寫入文件功能,它工作完美。與

ping google.com 

但它不能與我需要的命令...我需要啓動ffmpeg。命令,我需要的是

ffmpeg -i "my rtsp link" -vcodec copy -loglevel verbose -an -f flv "my RTMP link

,當我把我的命令,這段代碼裏面1-看到我瞬間輸出。2-沒有保存在文件中(

import subprocess 
import threading 
from datetime import datetime 
from time import sleep 
from Queue import Queue 

class Monitor(threading.Thread): 

    def __init__(self, queue, cmd): 
     super(Monitor, self).__init__() 
     self.queue = queue 
     self.cmd = cmd 

    def run(self): 
     popen = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, shell=True) 
     while popen.poll() is None: 
      line = popen.stdout.readline() 
      self.queue.put(line)  

def foo(cmd, interval): 

    q = Queue() 
    m = Monitor(q, cmd) 
    m.start() 

    while m.is_alive(): 
     sleep(interval) 
     current_queue_length = q.qsize() 
     chunk = '' 
     for i in xrange(current_queue_length): 
      chunk += q.get() 
    print chunk 
    f=open("/home/pi/raf/log.txt","a") #trying to write to log 
    f.write(chunk)  
    f.close() 


if __name__ == '__main__': 
    cmd = 'ping google.com' 
    interval = 3 
    foo(cmd, interval) 
相關問題