我正在尝试运行命令,获取它的输出,然后在同一环境中运行另一个命令(比如我在第一个命令中设置了一个环境变量,我希望它可用于第二个命令命令)。我试过这个:
import subprocess
process = subprocess.Popen("/bin/bash", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE);
process.stdin.write("export MyVar=\"Test\"\n")
process.stdin.write("echo $MyVar\n")
process.stdin.flush()
stdout, stderr = process.communicate()
print "stdout: " + str(stdout)
# Do it again
process.stdin.write("echo $MyVar\n")
process.stdin.flush()
stdout, stderr = process.communicate()
print "stdout: " + str(stdout)
但是communic()会一直读到最后,所以这不是一种有效的技术。 (我明白了:)
stdout: Test
Traceback (most recent call last):
File "./MultipleCommands.py", line 15, in <module>
process.stdin.write("echo $MyVar\n")
ValueError: I/O operation on closed file
我已经看到了这一点:https://stackoverflow.com/a/15654218/284529,但它没有提供一个如何做它所建议的工作示例。任何人都可以演示如何做到这一点? 我还看到了其他涉及在循环中不断检查输出的技术,但这并不适合&#34;得到命令的输出&#34;心态 - 它只是像流一样对待它。
答案 0 :(得分:1)
communicate
对象的{p> wait
和Popen
方法,在进程返回后关闭PIPE
。如果您希望与流程保持沟通,请尝试以下方法:
import subprocess
process = subprocess.Popen("/bin/bash", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE);
process.stdin.write("export MyVar=\"Test\"\n")
process.stdin.write("echo $MyVar\n")
process.stdin.flush()
process.stdout.readline()
process.stdin.write("echo $MyVar\n")
process.stdin.flush()
stdout, stderr = process.communicate()
print "stdout: " + str(stdout)
我认为你误解了沟通......
看看这个链接: - http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate
communication将一个字符串发送到另一个进程,然后等待它完成...(就像你说的等待EOF听stdout&amp; stderror)
你应该做的是:
proc.stdin.write('message')
# ...figure out how long or why you need to wait...
proc.stdin.write('message2')
(如果您需要获取stdout或stderr,请使用proc.stdout或proc.stderr)
答案 1 :(得分:1)
要获取多个命令的输出,只需将它们组合成一个脚本:
#!/usr/bin/env python
import subprocess
import sys
output = subprocess.check_output("""
export MyVar="Test"
echo $MyVar
echo ${MyVar/est/ick}
""", shell=True, executable='/bin/bash', universal_newlines=True)
sys.stdout.write(output)
Test
Tick
答案 2 :(得分:0)
当使用communicate
时,它看到子进程已经结束,但是如果你有一个中间的(bash),当你的子子进程结束时,你必须以某种方式手动发出信号。
至于其余部分,最简单的方法是发射标记线。但是,我很抱歉在这里让你失望但是汇集(即不断检查循环)实际上是the only sane option。如果您不喜欢循环,可以在函数中“隐藏”它。
import subprocess
import time
def readlines_upto(stream, until="### DONE ###"):
while True:
line = stream.readline()
if line is None:
time.sleep(0.1)
continue
if line.rstrip() == until:
break
yield line
process = subprocess.Popen("/bin/bash", shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.stdin.write("export MyVar=\"Test\"\n")
process.stdin.write("echo $MyVar\n")
process.stdin.write("echo '### DONE ###'\n")
process.stdin.flush()
# Note, I don't read stderr here, so if subprocess outputs too much there,
# it'll fill the pipe and stuck. If you don't need stderr data, don't
# redirect it to a pipe at all. If you need it, make readlines read two pipes.
stdout = "".join(line for line in readlines_upto(process.stdout))
print "stdout: " + stdout
# Do it again
process.stdin.write("echo $MyVar\n")
process.stdin.flush()
stdout, stderr = process.communicate()
print "stdout: " + str(stdout)
答案 3 :(得分:0)
根据手册:
Popen
。communicate
(输入=无)与流程交互:将数据发送到stdin。从stdout和stderr读取数据,直到达到文件结尾。 等待进程 终止。 [...]
您需要从管道中读取:
import os
stdout = os.read(process.stdout.fileno(), 1024)
print "stdout: " + stdout
如果没有数据等待,它将永久挂起或直到数据准备好被读取。您应该使用select
系统调用来阻止:
import select
import os
try:
i,o,e = select.select([process.stdout], [], [], 5) # 5 second timeout
stdout = os.read(i[0].fileno(), 1024)
except IndexError:
# nothing was written to the pipe in 5 seconds
stdout = ""
print "stdout: " + stdout
如果你想获取多次写入,为了避免竞争条件,你必须把它放在一个循环中:
stdout = ""
while True:
try:
i,o,e = select.select([process.stdout], [], [], 5) # 5 second timeout
stdout += os.read(i[0].fileno(), 1024)
except IndexError:
# nothing was written to the pipe in 5 seconds, we're done here
break