3

\nPython 3 (Linux または MacOSX10.8) では、サブプロセスによって発行されたプロンプト (を含まない) だけを親プロセスに読み取らせるにはどうすればよい\nですか?

# program names.py
print("I am Joe.")                   #1print
name = input("What is your name? ")  #2prompt
print("Hi", name, "!")               #3print

# program parent.py (in python 3.3.0)
import subprocess
import sys
p = subprocess.Popen([sys.executable, "names.py"],
                      bufsize=0,
                      stdin =subprocess.PIPE,
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE,
                      shell=False,
                      universal_newlines=True
                    )
print(p.stdout.readline(), end='')
p.stdin.write("Sue\n")
# The next print will produce the output of 2prompt + 3print:
print(p.stdout.readline(), end='')

実行すると、次のようparent.pyに出力されます。

I am Joe.
What is your name? Hi Sue !

parent.py印刷するように変更する方法:

I am Joe.
What is your name? 
Hi Sue !

つまり、プロンプトと印刷によって生成された出力を別々に抽出する方法は?

4

2 に答える 2

2

readline()names.pyここ\nで必要なのは「今ある分だけ読む」ことです。names.pyが待機中 (入力を期待)であることを基本的に検出する必要があるため、ここでは時間も追加の要素です。

read()基本的に、タイムアウト付きの操作が必要です。names.pyバイトごとにバッファに読み込む別のスレッドを開始できます。その後、join(timeout)このスレッドとそのバッファにアクセスできます。

于 2013-04-09T00:26:46.103 に答える
0

プロンプトがどのように見えるかを知っている場合は、@Michael が提案したように、文字列操作を使用して目的の出力を取得できます。

import sys
from subprocess import Popen, PIPE

p = Popen([sys.executable, "names.py"], stdin=PIPE, stdout=PIPE,
          universal_newlines=True)
output = p.communicate("Sue\n")[0]
prompt = "name? "
print(output.replace(prompt, prompt + "\n"))

出力

I am Joe.
What is your name? 
Hi Sue !

プロンプトがどのように表示されるかわからない場合、子プロセスが非対話的に実行されるときにブロックバッファリングを使用すると、@Exp が提案するタイムアウトベースのソリューションが機能しない可能性があります。それは動作しますがnames.pyselect出力を読み取るためにスレッドの代わりに使用するタイムアウトベースのソリューションを次に示します。

import os
import sys
from select import select
from subprocess import Popen, PIPE

timeout = 1 # seconds
with Popen([sys.executable, 'names.py'],
           stdin=PIPE, stdout=PIPE,  bufsize=0) as p:
    while True:
        ready = select([p.stdout], [], [], timeout)[0]
        if ready: # there is something to read
            data = os.read(p.stdout.fileno(), 512)
            if not data: # EOF
                break
            sys.stdout.buffer.write(data) # echo subprocess output
        elif p.poll() is None: # timeout, but subprocess is still running
            print("") # print newline after the prompt
            p.stdin.write(b"Sue\n") # answer the prompt
        else: # subprocess exited
            break

遅延の後、最初のコード例と同じ出力が生成されます。

一般にpexpect、サブプロセスの対話モードをエミュレートするために使用できます。

プロンプトがどのように見えるかを知っている場合:

import sys
import pexpect

print(pexpect.run(sys.executable + " -mnames", events={r'name\? ': 'Sue\n'}))
# note: it echos our answer too (it can be avoided if necessary)

出力

I am Joe.
What is your name? Sue
Hi Sue !

応答のエコーバックを回避するタイムアウトベースのソリューションを次に示します。

import sys
import pexpect # pip install pexpect-u

child = pexpect.spawn(sys.executable + " -mnames", timeout=1)
child.logfile_read = sys.stdout # echo subprocess output
child.expect(pexpect.TIMEOUT)
print("") # print newline after the prompt
child.setecho(False) # don't echo our answer
child.sendline('Sue')
child.expect(pexpect.EOF)
child.close()

を使用して再現するにはsubprocessptyモジュールを使用できます。

import os
import pty
import sys
from select import select
from subprocess import Popen, STDOUT

timeout = 1 # seconds
master_fd, slave_fd = pty.openpty()
with Popen([sys.executable, 'names.py'],
           stdin=slave_fd, stdout=slave_fd, stderr=STDOUT,
           bufsize=0) as p:
    while True:
        ready = select([master_fd], [], [], timeout)[0]
        if ready: # there is something to read
            data = os.read(master_fd, 512)
            if not data: # EOF
                break
            sys.stdout.buffer.write(data) # echo subprocess output
        elif p.poll() is None: # timeout, but subprocess is still running
            # assume that child process waits for input after printing the prompt
            answer = b"Sue\n"
            os.write(master_fd, answer) # asnwer the prompt
            os.read(master_fd, len(answer)) # don't echo our answer
        else: # subprocess exited
            break
    os.close(slave_fd)
    os.close(master_fd)
于 2013-04-09T17:05:22.323 に答える