20

以下のロジックに従う Python (2.6.5) 内から実行したいスクリプトがあります。

  • ユーザーにパスワードを要求します。("パスワードを入力してください: ") のようになります (*注: 入力は画面にエコーしません)
  • 無関係な情報を出力する
  • ユーザーに応答を求める ("Blah Blah filename.txt blah blah (Y/N)?: ")

最後のプロンプト行には、解析する必要があるテキスト (filename.txt) が含まれています。提供される応答は問題ではありません (行を解析できる限り、プログラムは応答を提供せずにここで実際に終了する可能性があります)。

私の要件は、インタラクティブなコマンドラインアプリケーションをPythonスクリプトでラップすることに多少似ていますが、そこの応答は少し混乱しているように見えます.OPが彼には向いていないと述べていても、私のものはまだハングしています.

周りを見回して、これがsubprocess最善の方法であるという結論に達しましたが、いくつかの問題があります。これが私のPopenラインです:

p = subprocess.Popen("cmd", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
  • read()またはreadline()を呼び出すとstdout、プロンプトが画面に表示され、ハングします。

  • write("password\n")forを呼び出すとstdin、プロンプトが画面に書き込まれ、ハングします。のテキストwrite()は書き込まれません (カーソルが新しい行に移動しません)。

  • を呼び出すとp.communicate("password\n")、write() と同じ動作になります

stdin入力する最良の方法と、おそらく出力の最後の行を解析する方法について、ここでいくつかのアイデアを探していました。

4

2 に答える 2

15

サブプロセスが生成するプログラムと通信している場合は、A non-blocking read on a subprocess.PIPE in Python を確認してください。私のアプリケーションにも同様の問題があり、キューを使用することがサブプロセスとの継続的な通信を行う最良の方法であることがわかりました。

ユーザーから値を取得する場合は、いつでも raw_input() ビルトインを使用して応答を取得できます。パスワードについては、getpassモジュールを使用してユーザーから非エコー パスワードを取得してみてください。次に、これらの応答を解析して、サブプロセスの stdin に書き込むことができます。

私は最終的に次のようなことをしました:

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)

キューを作成してスレッドを開始したら、ユーザーからの入力の取得、プロセスからのエラーと出力の取得、およびそれらの処理とユーザーへの表示をループできます。

于 2012-11-19T16:51:57.740 に答える
1

スレッド化を使用すると、単純なタスクでは少し過剰になる可能性があります。代わりに os.spawnvpe を使用できます。スクリプト シェルをプロセスとして生成します。スクリプトと対話的に通信できるようになります。この例では、パスワードを引数として渡しましたが、これは明らかに良い考えではありません。

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
于 2015-04-06T20:41:16.173 に答える