【发布时间】:2012-01-07 06:34:31
【问题描述】:
我正在尝试从子进程获取输出,然后根据前面的输出向该进程发出命令。当程序需要进一步输入时,我需要多次执行此操作。 (如果可能,我还需要能够隐藏子进程命令提示符)。
我认为这将是一项简单的任务,因为我已经看到在 2003 年的帖子中讨论过这个问题,现在已经快 2012 年了,这似乎是一个非常普遍的需求,而且看起来它应该是任何问题的基本组成部分编程语言。显然我错了,不知何故,将近 9 年后,仍然没有以稳定、非破坏性、独立于平台的方式完成这项任务的标准方法!
我不太了解文件 i/o 和缓冲或线程,因此我更喜欢尽可能简单的解决方案。如果有一个与 python 3.x 兼容的模块,我会非常愿意下载它。我意识到有多个问题的问题基本相同,但我还没有找到解决我想要完成的简单任务的答案。
这是我目前基于各种来源的代码;但是我完全不知道下一步该做什么。我所有的尝试都以失败告终,有些人设法使用了我 100% 的 CPU(基本上什么都不做)并且不会退出。
import subprocess
from subprocess import Popen, PIPE
p = Popen(r'C:\postgis_testing\shellcomm.bat',stdin=PIPE,stdout=PIPE,stderr=subprocess.STDOUT shell=True)
stdout,stdin = p.communicate(b'command string')
如果我的问题不清楚,我将发布示例批处理文件的文本,我演示了需要向子进程发送多个命令的情况(如果您键入不正确的命令字符串,程序将循环)。
@echo off
:looper
set INPUT=
set /P INPUT=Type the correct command string:
if "%INPUT%" == "command string" (echo you are correct) else (goto looper)
如果有人可以帮助我,我将不胜感激,我相信许多其他人也会如此!
这里编辑的是使用 eryksun 的代码的功能代码(下一篇):
import subprocess
import threading
import time
import sys
try:
import queue
except ImportError:
import Queue as queue
def read_stdout(stdout, q, p):
it = iter(lambda: stdout.read(1), b'')
for c in it:
q.put(c)
if stdout.closed:
break
_encoding = getattr(sys.stdout, 'encoding', 'latin-1')
def get_stdout(q, encoding=_encoding):
out = []
while 1:
try:
out.append(q.get(timeout=0.2))
except queue.Empty:
break
return b''.join(out).rstrip().decode(encoding)
def printout(q):
outdata = get_stdout(q)
if outdata:
print('Output: %s' % outdata)
if __name__ == '__main__':
#setup
p = subprocess.Popen(['shellcomm.bat'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
bufsize=0, shell=True) # I put shell=True to hide prompt
q = queue.Queue()
encoding = getattr(sys.stdin, 'encoding', 'utf-8')
#for reading stdout
t = threading.Thread(target=read_stdout, args=(p.stdout, q, p))
t.daemon = True
t.start()
#command loop
while p.poll() is None:
printout(q)
cmd = input('Input: ')
cmd = (cmd + '\n').encode(encoding)
p.stdin.write(cmd)
time.sleep(0.1) # I added this to give some time to check for closure (otherwise it doesn't work)
#tear down
for n in range(4):
rc = p.poll()
if rc is not None:
break
time.sleep(0.25)
else:
p.terminate()
rc = p.poll()
if rc is None:
rc = 1
printout(q)
print('Return Code: %d' % rc)
但是,当从命令提示符运行脚本时,会发生以下情况:
C:\Users\username>python C:\postgis_testing\shellcomm7.py
Input: sth
Traceback (most recent call last):
File "C:\postgis_testing\shellcomm7.py", line 51, in <module>
p.stdin.write(cmd)
IOError: [Errno 22] Invalid argument
从命令提示符运行时,程序似乎关闭了。有什么想法吗?
【问题讨论】:
标签: python shell command-line subprocess asynchronous