【问题标题】:Prevent creating new child process using subprocess in Python防止在 Python 中使用子进程创建新的子进程
【发布时间】:2014-09-15 18:42:39
【问题描述】:

我需要从 Python 运行大量 bash 命令。目前我正在这样做
subprocess.Popen(cmd, shell=True)

是否有任何解决方案可以在同一个 shell 中运行所有这些命令? subprocess.Popen 在每次执行时都会打开一个新的 shell,我需要在每次调用时设置所有必要的变量,以便 cmd 命令正常工作。

【问题讨论】:

  • 您运行的每个命令仍然是一个子进程,并且是您的脚本或由您的脚本生成的 shell 的子进程。您需要孩子和脚本之间的外壳吗?
  • 在每个 subprocess.Popen 我需要导出一个变量并在同一个调用中运行 cmd 命令。这将产生丑陋的语法。最好只导出一次该变量,然后运行我的 cmd 命令。
  • 除非你真的需要使用subprocess.Popen(),否则你应该使用multiprocessing.Process。 (您的所有作业都是独立且不同步的吗?您是否需要担心在作业序列的中间捕获非零错误状态?)
  • OP,你应该告诉我们“很多 bash 命令”是什么。如果它们是可执行文件,则已经使用多处理调用可执行文件;如果它们是 bash 内置程序,那么您无需费力 bash 来执行此操作。你到底想做什么?
  • @smci,嗯? multiprocessing 专门用于子进程也是 Python 的情况,这在此处听起来并非如此。如果你想使用没有 shell 的子进程,subprocess 模块就可以了——只是永远不要使用shell=True 或将cmd 作为字符串传递。

标签: python bash subprocess parent-child popen


【解决方案1】:

subprocess.Popen 允许您提供环境变量字典,它将成为正在运行的进程的环境。如果您需要shell=True 的唯一原因是设置环境变量,那么我建议您改用显式环境字典;它更安全,也不是特别困难。此外,当您不必担心引用和 shell 元字符时,通常更容易构造命令调用。

如果您不介意在运行进程中设置环境变量,甚至可能不需要构建环境字典。 (大多数情况下,这不会是问题,但有时会。我对您的应用程序了解得不够多。)

如果您可以使用设置修改自己的环境,请这样做:

os.environ['theEnvVar'] = '/the/value' 

然后你可以使用一个简单的Popen.call(或类似的)来运行命令:

output = subprocess.check_output(["ls", "-lR", "/tmp"])

如果由于某种原因您无法更改自己的环境,则需要复制当前环境,根据需要进行修改,并将其传递给每个subprocess.call

env = os.environ.copy()
env['theEnvVar'] = '/the/value'
output = subprocess.check_output(["ls", "-lR", "/tmp"], env=env)

如果您不想每次都指定env=env,只需编写一个小包装类即可。

【讨论】:

    【解决方案2】:

    为什么不直接创建一个包含您需要运行的所有命令的 shell 脚本,然后只使用一个 subprocess.Popen() 调用来运行它?如果您需要运行的命令内容取决于 Python 脚本中计算的结果,您可以动态创建 shell 脚本,然后运行它。

    【讨论】:

    • 我的命令被其他python操作隔开。我不知道如何做到这一点,但我想它会导致复杂的语法。
    • 只有一个外壳仍然比零外壳更糟糕。我看不出为什么我们不能有零 shell 的任何理由——使用显式 argv 数组调用每个命令,因此(隐式)shell=False
    【解决方案3】:

    改用multiprocessing,它更轻量级和高效。

    与 subprocess.Popen 不同,它不会在每次执行时打开一个新的 shell。

    你没有说你需要运行subprocess.Popen,你很可能不需要;你刚才说这就是你目前正在做的事情。请提供更多理由。

    请参阅set env var in Python multiprocessing.Process,了解如何在父进程中一劳永逸地设置环境变量。

    【讨论】:

    • 你能解释一下multiprocessing 在这里实际上会有什么帮助吗?
    • 因为与 subprocess.Popen 不同,它不会在每次执行时打开一个新的 shell,这是 OP 抱怨的。您是否考虑过不对正确答案投反对票?这是无理取闹和破坏性的。
    • 我没有投反对票。 subprocess.Popen 执行子进程。 multiprocessing.Process 在另一个进程中执行 python 可调用(如函数)。您将如何使用 multiprocessing.Process 在单个 shell 中执行一堆 bash 命令,就像 OP 想要的那样?
    • 如果 OP 想要调用可执行文件,那么只需调用可执行文件。 OP 没有说他们需要运行subprocess.Popen。他们只是说这就是他们目前正在做的事情。
    • @smci,声称subprocess.Popen() 在每次执行时打开一个新外壳是错误的。它仅在与shell=True 一起使用或与为cmd 传递的字符串一起使用时才会这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 2011-10-12
    • 2017-04-18
    相关资源
    最近更新 更多