2009-08-15 23 views
5

Tôi muốn ghi lại giá trị xuất phát từ quá trình chạy dài được bắt đầu qua subprocess.Popen(...) vì vậy tôi đang sử dụng stdout=PIPE làm arg. Tuy nhiên, bởi vì nó là một quá trình chạy dài, tôi cũng muốn gửi đầu ra cho bàn điều khiển (như thể tôi đã không cho nó) để cung cấp cho người dùng kịch bản ý tưởng rằng nó vẫn đang hoạt động.Python - chụp Popen stdout VÀ hiển thị trên bảng điều khiển?

Điều này có thể thực hiện được không?

Chúc mừng.

+0

Trùng lặp: http://stackoverflow.com/questions/803265/getting-realtime-output-using-subprocess and http : //stackoverflow.com/questions/874815/how-do-i-get-real-time-information-back-from-a-subprocess-popen-in-python-2-5 –

+0

liên quan: [Python: đọc trực tuyến đầu vào từ subprocess.communicate()] (http://stackoverflow.com/a/17698359/4279) – jfs

Trả lời

1

Bạn có thể chỉ cần print khi bạn đọc nó từ ống?

+0

Ah! (light bulb moment!) - p.stdout là một tập tin như đối tượng. Vì vậy, tôi chỉ cần gọi readline() trên nó trong một vòng lặp? Đúng? Cách tốt nhất để thoát khỏi vòng lặp là gì - khi p.stdout trả về chuỗi rỗng? Tôi vẫn nên làm p.wait() sau khi chỉ để chắc chắn? –

+1

@Steve: Một chuỗi rỗng trả về từ đọc p.stdout có nghĩa là đứa trẻ đã đóng cửa stdout của nó, nhưng không nhất thiết là nó đã kết thúc. p.wait() sẽ đợi nó chấm dứt. – RichieHindle

5

Quá trình đệm mà quy trình phụ chạy dài của bạn có thể đang hoạt động sẽ khiến cho giao diện điều khiển của bạn bị giật và UX rất tệ. Tôi khuyên bạn nên xem xét thay vì sử dụng pexpect (hoặc, trên Windows, wexpect) để đánh bại bộ đệm như vậy và nhận được kết quả đầu ra thông thường từ quy trình phụ. Ví dụ: (chỉ về bất kỳ hệ thống unix-y nào, sau khi cài đặt pexpect):

>>> import pexpect 
>>> child = pexpect.spawn('/bin/bash -c "echo ba; sleep 1; echo bu"', logfile=sys.stdout); x=child.expect(pexpect.EOF); child.close() 
ba 
bu 
>>> child.before 
'ba\r\nbu\r\n' 

Ba và bu sẽ có thời gian thích hợp (khoảng một giây). Lưu ý đầu ra không phải xử lý thiết bị đầu cuối bình thường, do đó, trả về vận chuyển được để lại trong đó - bạn sẽ cần phải tự xử lý chuỗi (chỉ đơn giản là .replace! -) nếu bạn cần \n là cuối dòng đánh dấu (việc thiếu xử lý là quan trọng chỉ trong trường hợp quá trình con đang viết dữ liệu nhị phân để stdout của nó - điều này đảm bảo tất cả các dữ liệu còn nguyên vẹn! -).

1

Hoặc, bạn có thể đưa quy trình của bạn vào tee và chỉ chụp một trong các luồng. Có gì đó dọc theo các dòng sh -c 'process interesting stuff' | tee /dev/stderr.

Tất nhiên, điều này chỉ hoạt động trên các hệ thống giống Unix.

+1

Thật không may vẫn chịu sự giật giật gây ra bởi bộ đệm :-(. –

2

S. Lott của điểm bình luận cho Getting realtime output using subprocessReal-time intercepting of stdout from another process in Python

tôi tò mò rằng câu trả lời của Alex ở đây là khác biệt so với câu trả lời của ông 1085071. thí nghiệm đơn giản, ít của tôi với những câu trả lời trong hai câu hỏi tham khảo khác đã cho kết quả tốt ...

Tôi đã đi và nhìn wexpect theo câu trả lời của Alex ở trên, nhưng tôi phải nói đọc các ý kiến ​​trong mã tôi đã không để lại một cảm giác rất tốt về việc sử dụng nó.

Tôi đoán câu hỏi meta ở đây là khi nào sẽ mong đợi/wexpect là một trong các pin được bao gồm?

1

Lấy cảm hứng từ đề xuất pty.openpty() ở đâu đó ở trên, được thử nghiệm trên python2.6, linux. Xuất bản vì phải mất một lúc để làm cho hoạt động này hoạt động đúng cách, hãy lưu vào bộ đệm ...

def call_and_peek_output(cmd, shell=False): 
    import pty, subprocess 
    master, slave = pty.openpty() 
    p = subprocess.Popen(cmd, shell=shell, stdin=None, stdout=slave, close_fds=True) 
    os.close(slave) 
    line = "" 
    while True: 
     try: 
      ch = os.read(master, 1) 
     except OSError: 
      # We get this exception when the spawn process closes all references to the 
      # pty descriptor which we passed him to use for stdout 
      # (typically when it and its childs exit) 
      break 
     line += ch 
     sys.stdout.write(ch) 
     if ch == '\n': 
      yield line 
      line = "" 
    if line: 
     yield line 

    ret = p.wait() 
    if ret: 
     raise subprocess.CalledProcessError(ret, cmd) 

for l in call_and_peek_output("ls /", shell=True): 
    pass 
Các vấn đề liên quan