2009-07-14 29 views
7

Tôi đang sử dụng python 2,5 trên Windows. Tôi muốn tương tác với một giao diện điều khiển thông qua Popen. Tôi hiện có đoạn mã nhỏ này:Tương tác với ứng dụng bảng điều khiển Windows qua Python

p = Popen(["console_app.exe"], stdin=PIPE, stdout=PIPE) 
# issue command 1... 
p.stdin.write('command1\n') 
result1 = p.stdout.read() # <---- we never return here 
# issue command 2... 
p.stdin.write('command2\n') 
result2 = p.stdout.read() 

Tôi có thể viết thành stdin nhưng không thể đọc từ stdout. Tôi đã bỏ lỡ một bước chưa? Tôi không muốn sử dụng p.communicate ("command") [0] vì nó chấm dứt quá trình và tôi cần phải tương tác với quá trình động theo thời gian.

Xin cảm ơn trước.

+0

Mã của bạn có vẻ chính xác. Console_app có hoạt động tốt khi bạn thực hiện từ giao diện điều khiển không? Nó trả về cho lệnh1 là gì? – luc

+0

yes console_app hoạt động bình thường khi chạy trong cmd.exe Nó chỉ xuất ra một số số dựa trên đầu vào được cung cấp (và đôi khi dây) – QAZ

Trả lời

0

Tôi nghĩ bạn có thể muốn thử sử dụng readline() thay thế?

Chỉnh sửa: xin lỗi, hiểu nhầm.

Có thể this câu hỏi có thể giúp bạn?

+0

readline() cũng bị treo. Tôi có thể xác nhận rằng ứng dụng giao diện điều khiển thực hiện dữ liệu đầu ra cần được đọc chính xác ở phía bên python. – QAZ

0

Có thể ứng dụng bảng điều khiển đang lưu vào bộ đệm của nó theo một cách nào đó để nó chỉ được gửi tới chế độ chờ khi ống được đóng? Nếu bạn có quyền truy cập vào mã cho ứng dụng giao diện điều khiển, có thể bạn sẽ bị xóa sau khi một loạt dữ liệu đầu ra có thể trợ giúp?

Ngoài ra, nó thực sự là viết để stderr và thay vì stdout vì một lý do nào đó?

Chỉ cần nhìn lại mã của bạn và nghĩ về một thứ khác, tôi thấy bạn đang gửi "lệnh \ n". Ứng dụng giao diện điều khiển có thể đơn giản chờ một ký tự trả về thay vì dòng mới không? Có lẽ ứng dụng giao diện điều khiển đang chờ bạn gửi lệnh trước khi nó tạo ra bất kỳ đầu ra nào.

+0

Cảm ơn, những gợi ý tốt. Tôi không có quyền truy cập vào mã nguồn của ứng dụng giao diện điều khiển không may. Xác nhận văn bản của nó để stdout và không stderr. – QAZ

0

Có cùng vấn đề chính xác ở đây. Tôi đào vào mã nguồn DrPython và lấy trộm giải pháp wx.Execute(), hoạt động tốt, đặc biệt nếu tập lệnh của bạn đã sử dụng wx. Tôi không bao giờ tìm thấy giải pháp chính xác trên nền tảng cửa sổ mặc dù ...

7

Vấn đề của bạn ở đây là bạn đang cố gắng kiểm soát một ứng dụng tương tác.

stdout.read() sẽ tiếp tục đọc cho đến khi nó đến cuối luồng, tệp hoặc đường ống. Thật không may, trong trường hợp của một chương trình tương tác, đường ống chỉ đóng cửa sau đó thoát khỏi chương trình; đó là không bao giờ, nếu lệnh bạn gửi nó là bất cứ điều gì khác hơn là "quit".

Bạn sẽ phải hoàn nguyên để đọc đầu ra của tiến trình con theo từng dòng bằng cách sử dụng stdout.readline() và bạn nên có cách để biết thời điểm chương trình sẵn sàng chấp nhận lệnh và khi lệnh bạn đã phát hành để chương trình kết thúc và bạn có thể cung cấp chương trình mới. Trong trường hợp của một chương trình như cmd.exe, thậm chí readline() sẽ không đủ vì dòng chỉ ra một lệnh mới có thể được gửi không bị chấm dứt bởi một dòng mới, do đó, sẽ phải phân tích đầu ra byte-by-byte. Dưới đây là một kịch bản mẫu chạy cmd.exe, tìm kiếm dấu nhắc, sau đó đưa ra một dir và sau đó một exit:

from subprocess import * 
import re 

class InteractiveCommand: 
    def __init__(self, process, prompt): 
     self.process = process 
     self.prompt = prompt 
     self.output = "" 
     self.wait_for_prompt() 

    def wait_for_prompt(self): 
     while not self.prompt.search(self.output): 
      c = self.process.stdout.read(1) 
      if c == "": 
       break 
      self.output += c 

     # Now we're at a prompt; clear the output buffer and return its contents 
     tmp = self.output 
     self.output = "" 
     return tmp 

    def command(self, command): 
     self.process.stdin.write(command + "\n") 
     return self.wait_for_prompt() 

p  = Popen(["cmd.exe"], stdin=PIPE, stdout=PIPE) 
prompt = re.compile(r"^C:\\.*>", re.M) 
cmd = InteractiveCommand(p, prompt) 

listing = cmd.command("dir") 
cmd.command("exit") 

print listing 

Nếu thời gian là không quan trọng, và tương tác cho người dùng được không cần thiết, nó có thể được rất nhiều đơn giản chỉ để hàng loạt lên các cuộc gọi:

from subprocess import * 

p = Popen(["cmd.exe"], stdin=PIPE, stdout=PIPE) 
p.stdin.write("dir\n") 
p.stdin.write("exit\n") 

print p.stdout.read() 
+1

Nó sẽ không hoạt động trên các cửa sổ như .read (1) đang chặn hoạt động –

+0

Tôi biết, đó là lý do tại sao sau mỗi byte script kiểm tra nếu lời nhắc có sẵn và viết lệnh mới sau đó trước khi đọc thêm byte. Thậm chí bạn có thử kịch bản không? Nó hoạt động. – rix0rrr

+0

Phải, tôi không nhận ra ngay từ cái nhìn đầu tiên. +1 để triển khai tốt đẹp. –

2

bạn đã cố gắng để buộc dòng cửa sổ kết thúc? tức là

p.stdin.write('command1 \r\n') 
p.stdout.readline() 

UPDATE:

Tôi vừa mới kiểm tra các giải pháp trên cửa sổ cmd.exe và nó hoạt động với readline(). Nhưng nó có một vấn đề stdout.readline Popen khối. Vì vậy, nếu ứng dụng sẽ bao giờ trở lại một cái gì đó mà không có dòng cuối ứng dụng của bạn sẽ bị mắc kẹt mãi mãi.

Nhưng có một công việc xung quanh để kiểm tra: http://code.activestate.com/recipes/440554/

Các vấn đề liên quan