如何将打印和stdout重定向到管道,并从父进程读取?

0 投票
2 回答
3362 浏览
提问于 2025-04-30 21:23

如果可以的话,我希望不使用 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环境的命令——它们会被执行,但不会产生任何效果。

撰写回答