2012-07-12 47 views
18

Tôi có một kịch bản mà tôi muốn chạy từ bên trong python (2.6.5) mà sau logic dưới đây:Chạy một lệnh tương tác từ bên trong python

  • Nhắc người dùng nhập mật khẩu. Có vẻ như ("Nhập mật khẩu:") (* Lưu ý: Đầu vào không phản hồi màn hình)
  • Thông tin không liên quan đến đầu ra
  • Nhắc người dùng trả lời ("Blah Blah filename.txt blah blah (Y/N) ?:")

Dòng nhắc cuối cùng chứa văn bản cần phân tích cú pháp (filename.txt). Phản hồi được cung cấp không quan trọng (Chương trình có thể thực sự thoát ra ở đây mà không cung cấp, miễn là tôi có thể phân tích cú pháp dòng)

Yêu cầu của tôi là tương tự Wrapping an interactive command line application in a python script. Có lẽ chỉ hơi dày một chút, nhưng câu trả lời có vẻ hơi khó hiểu, và tôi vẫn bị treo ngay cả khi OP đề cập rằng nó không 'cho anh ta.

Thông qua tìm kiếm xung quanh, tôi đi đến kết luận rằng quy trình con là cách tốt nhất để thực hiện việc này, nhưng Im có một số vấn đề. Popen dòng dưới

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT, stdin=subprocess.PIPE) 
  • Khi tôi gọi một read() hoặc readline() trên thiết bị xuất chuẩn, dấu nhắc là máy in để màn hình và nó bị treo.

  • Nếu tôi gọi ghi ("password \ n") cho stdin, dấu nhắc được ghi lên màn hình và nó bị treo. Các văn bản trong write() không được viết (Tôi không di chuyển con trỏ một dòng mới).

  • Nếu tôi gọi p.communicate ("password \ n"), hành vi tương tự như ghi()

tôi đang tìm kiếm một vài ý tưởng ở đây về cách tốt nhất để đầu vào stdin và có thể làm thế nào để phân tích dòng cuối cùng trong đầu ra nếu cảm giác của bạn hào phóng, mặc dù tôi có thể có thể con số đó ra cuối cùng. Cảm ơn!

+3

Bạn nên nhìn vào Pexpect: http://www.noah.org/wiki/pexpect –

+0

Tôi nghĩ rằng bạn cần phải viết thư cho stdout và đọc từ stdin ... không phải là otherway xung quanh như bạn đặt trên –

+0

@Joran haha ​​yeah, xin lỗi. Đó là điều tôi muốn nói. – user1521597

Trả lời

10

Nếu bạn đang kết nối với chương trình mà quy trình con sinh ra, bạn nên kiểm tra Non-blocking read on a subprocess.PIPE in python. Tôi đã có một vấn đề tương tự với ứng dụng của tôi và tìm thấy bằng cách sử dụng Hàng đợi là cách tốt nhất để thực hiện liên lạc liên tục với một tiến trình con.

Để nhận giá trị từ người dùng, bạn luôn có thể sử dụng nội dung raw_input() để nhận phản hồi và mật khẩu, hãy thử sử dụng mô-đun getpass để nhận mật khẩu không lặp lại từ người dùng của bạn. Sau đó bạn có thể phân tích các phản hồi đó và ghi chúng vào stdin của tiến trình con của bạn.

tôi đã kết thúc làm điều gì đó tương tự như sau:

import sys 
import subprocess 
from threading import Thread 

try: 
    from Queue import Queue, Empty 
except ImportError: 
    from queue import Queue, Empty # python 3.x 


def enqueue_output(out, queue): 
    for line in iter(out.readline, b''): 
     queue.put(line) 
    out.close() 


def getOutput(outQueue): 
    outStr = '' 
    try: 
     while True: #Adds output from the Queue until it is empty 
      outStr+=outQueue.get_nowait() 

    except Empty: 
     return outStr 

p = subprocess.Popen("cmd", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True) 

outQueue = Queue() 
errQueue = Queue() 

outThread = Thread(target=enqueue_output, args=(p.stdout, outQueue)) 
errThread = Thread(target=enqueue_output, args=(p.stderr, errQueue)) 

outThread.daemon = True 
errThread.daemon = True 

outThread.start() 
errThread.start() 

try: 
    someInput = raw_input("Input: ") 
except NameError: 
    someInput = input("Input: ") 

p.stdin.write(someInput) 
errors = getOutput(errQueue) 
output = getOutput(outQueue) 

Một khi bạn đã Queues thực hiện và đề bắt đầu, bạn có thể lặp qua nhận đầu vào từ người dùng, nhận lỗi và đầu ra từ quá trình này, và xử lý và hiển thị chúng cho người dùng.

0

Sử dụng luồng có thể hơi quá mức đối với các tác vụ đơn giản. Thay vì os.spawnvpe có thể được sử dụng. Nó sẽ sinh ra kịch bản shell như một quá trình. Bạn sẽ có thể giao tiếp tương tác với tập lệnh. Trong ví dụ này tôi đã thông qua mật khẩu như một đối số, rõ ràng nó là một ý tưởng không tốt.

import os 
import sys 
from getpass import unix_getpass 

def cmd(cmd): 
    cmd = cmd.split() 
    code = os.spawnvpe(os.P_WAIT, cmd[0], cmd, os.environ) 
    if code == 127: 
     sys.stderr.write('{0}: command not found\n'.format(cmd[0])) 
    return code 

password = unix_getpass('Password: ') 
cmd_run = './run.sh --password {0}'.format(password) 
cmd(cmd_run) 

pattern = raw_input('Pattern: ') 
lines = [] 
with open('filename.txt', 'r') as fd: 
    for line in fd: 
     if pattern in line: 
      lines.append(line) 

# manipulate lines 
Các vấn đề liên quan