以下のロジックに従って、python(2.6.5)内から実行したいスクリプトがあります。
最後のプロンプト行には、解析する必要があるテキストが含まれています(filename.txt)。提供された応答は重要ではありません(プログラムが行を解析できる限り、プログラムは提供せずに実際にここで終了できます)。
私の要件はsomewhatに似ています インタラクティブコマンドラインアプリケーションをpythonスクリプト)でラッピングする 、しかし、そこの反応は少し混乱しているようで、OPが彼のためではないと述べている場合でも、私の反応は依然としてハングしています。
振り返ってみると、subprocess
がこれを行う最良の方法であるという結論に達しましたが、いくつか問題があります。これが私のPopenラインです:
_p = subprocess.Popen("cmd", Shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
_
stdout
でread()
またはreadline()
を呼び出すと、プロンプトが画面に表示され、ハングします。
stdin
に対してwrite("password\n")
を呼び出すと、プロンプトが画面に表示されてハングします。 write()
のテキストは書き込まれません(カーソルで新しい行を移動しません)。
p.communicate("password\n")
を呼び出すと、write()と同じ動作になります
私はここでstdin
に入力する最良の方法と、寛大な気持ちで出力の最後の行を解析する方法についていくつかのアイデアを探していましたが、おそらく最終的にはそれを理解することができたでしょう。
サブプロセスが生成するプログラムと通信している場合は、 Pythonのsubprocess.PIPEでの非ブロッキング読み取り を確認してください。私のアプリケーションにも同様の問題があり、サブプロセスとの継続的な通信を行うには、キューを使用するのが最善の方法であることがわかりました。
ユーザーから値を取得する場合は、常に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)
キューを作成してスレッドを開始したら、ユーザーからの入力の取得、プロセスからのエラーと出力の取得、それらの処理とユーザーへの表示をループできます。
スレッド化を使用すると、単純なタスクでは少しやり過ぎになる場合があります。代わりに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