如何将打印和stdout重定向到管道,并从父进程读取?
如果可以的话,我希望不使用 subProcess.popen
。我想捕获子进程的输出(stdout),是因为我需要把子进程的输出保存到一个变量里,以便之后再显示出来。不过我到现在还没找到任何方法可以做到这一点。我还需要同时启动多个程序,而不一定要关闭当前正在运行的那个。我还需要通过父进程来控制子进程。
我这样启动一个子进程:
listProgram = ["./perroquet.py"]
listOutput = ["","",""]
tubePerroquet = os.pipe()
pipeMain = os.pipe()
pipeAge = os.pipe()
pipeSavoir = os.pipe()
pid = os.fork()
process = 1
if pid == 0:
os.close(pipePerroquet[1])
os.dup2(pipePerroquet[0],0)
sys.stdout = os.fdopen(tubeMain[1], 'w')
os.execvp("./perroquet.py", listProgram)
如你所见,我是用 os.execvp
启动程序,并使用 os.dup2()
来重定向子进程的输出。不过我对我在代码中做的事情不是很确定,想知道用 os.dup2
正确重定向输出的方法是什么,然后能在父进程中读取它。
谢谢你的帮助。
2 个回答
0
如果你需要提取环境中的任何变化,这里有一个解决方案。
from subprocess import Popen, PIPE
import os
def execute_and_get_env(cmd, initial_env=None):
if initial_env is None:
initial_env = os.environ
r_fd, w_fd = os.pipe()
write_env = "; env >&{}".format(w_fd)
p = Popen(cmd + write_env, shell=True, env=initial_env, pass_fds=[w_fd], stdout=PIPE, stderr=PIPE)
output, error = p.communicate()
# this will cause problems if the environment gets very large as
# writing to the pipe will hang because it gets full and we only
# read from the pipe when the process is over
os.close(w_fd)
with open(r_fd) as f:
env = dict(line[:-1].split("=", 1) for line in f)
return output, error, env
export_cmd = "export my_var='hello world'"
echo_cmd = "echo $my_var"
out, err, env = execute_and_get_env(export_cmd)
out, err, env = execute_and_get_env(echo_cmd, env)
print(out)
0
我不明白你为什么不想用很棒的subprocess模块,它可以帮你省去很多重复的代码(同时也减少出错的可能性)。无论如何,我假设perroquet.py
是一个Python脚本,而不是一个可执行程序。Shell知道如何找到脚本的正确解释器,但exec
这类函数是低级函数,它们期待的是一个真正的可执行程序。
你至少应该有类似这样的代码:
listProgram = [ "python", "./perroquet.py","",""]
...
os.execvp("python", listProgram)
但我更倾向于使用:
prog = subprocess.Popen(("python", "./perroquet.py", "", ""), stdout = PIPE)
或者,既然你已经在用Python了,可以直接导入它并调用里面的函数。
编辑:
看起来你真正想要的是:
- 用户给你一个命令(几乎可以是任何东西)
- [你验证这个命令是否安全] - 不确定你是否打算这样做,但你应该这么做...
- 让Shell执行这个命令并获取它的输出 - 你可能还想读取错误输出并控制退出代码
你可以尝试类似这样的代码:
while True:
cmd = raw_input("commande :") # input with Python 3
if cmd.strip().lower() == exit: break
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
out, err = proc.communicate()
code = proc.returncode
print("OUT", out, "ERR", err, "CODE", code)
这绝对是不安全的,因为这段代码会像底层的Shell那样执行任何命令(包括rm -rf *
、rd /s/q .
等),但它会给你命令的输出和返回代码,并且可以在循环中使用。唯一的限制是,由于你为每个命令使用不同的Shell,不能使用会改变Shell环境的命令——它们会被执行,但不会产生任何效果。