3

使用 Python,如何使用修改后的环境变量运行子进程并获取其 PID?我假设 subprocess.Popen() 是在正确的轨道上......

在 shell (bash) 中,我会这样做:

MY_ENV_VAR=value ./program_name arg1 arg2 etc &

program_name在后台运行,传入“arg1”、“arg2”和“etc”,并带有修改后的环境变量“MY_ENV_VAR”,其值为“value”。该程序program_name要求将环境变量MY_ENV_VAR设置为正确的值。

如何在 Python 中做同样的事情?我绝对需要进程的PID。(我的目的是保持 python 脚本运行并同时检查一些program_name正在做的事情,我需要进程 ID 以确保它仍在运行。)

我试过了:

proc = subprocess.Popen(['MY_ENV_VAR=value', './program_name', 'arg1', 'arg2', 'etc'])

但当然,它希望第一项是程序,而不是环境变量。

也试过:

environ = dict(os.environ)
environ['MY_ENV_VAR'] = 'value'
proc = subprocess.Popen(['./program_name', 'arg1', 'arg2', 'etc', env=environ])

接近,我想,但没有雪茄。同样,这个:

environ = dict(os.environ)
environ['MY_ENV_VAR'] = 'value'
proc = subprocess.Popen(['echo', '$MY_ENV_VAR'], env=environ)

这在字面上与“$MY_ENV_VAR”相呼应,我想是因为没有外壳可以解释它。好的,所以我尝试上面的方法,但改用这一行:

proc = subprocess.Popen(['echo', '$MY_ENV_VAR'], env=environ, shell=True)

这很好,很漂亮,除了回显的值是空白的(显然不存在)。即使它确实有效,我也会得到 shell 的 PID,而不是我试图启动的实际进程。

我需要使用自定义环境变量启动一个进程并获取它的 PID(不是 shell 的 PID)。想法?

4

2 回答 2

2

您的上一个版本非常接近,但不完全在那里。

你不想$MY_ENV_VAR成为echo. 该echo程序将MY_ENV_VAR在其环境中,但echo不进行任何环境变量扩展。你需要它被 shell 扩展,甚至在它到达echo.

这实际上可能与您的实际测试用例无关。您已经所有测试中为子进程获取了环境变量,只是对echo那个环境变量没有任何作用。如果您的真实程序只需要设置环境变量,那么您就完成了:

proc = subprocess.Popen(['./program_name', 'arg1', 'arg2', 'etc'], env=environ)

但是,如果您的程序需要替换它,例如echo,那么您必须在参数传递给您的程序之前将其替换为参数。

最简单的方法是只给 shell 一个命令行而不是参数列表:

proc = subprocess.Popen('echo "$MY_ENV_VAR"', env=environ, shell=True)

人们会告诉你,你永远不应该在其中使用命令字符串subprocess——但这样做的原因是你总是想防止 shell 以一种不安全的方式扩展变量等。在极少数情况下,当您希望shell 执行其外壳操作时,您需要一个命令字符串。

当然,如果你使用 shell,在大多数平台上,你最终会得到 shell 的 PID,而不是实际程序的 PID。如果没有做一些特定于平台的挖掘来枚举 shell 的孩子(或者将整个事情包装在一些简单的sh代码中,间接地给你孩子的 PID),没有办法解决这个问题。shell 就是你正在运行的东西。

另一种选择是在 Python 中扩展变量,而不是让 shell 来做。然后你甚至不需要外壳:

proc = subprocess.Popen(['echo', os.path.expandvars('$MY_ENV_VAR')])

……或者,更简单地说:

proc = subprocess.Popen(['echo', os.environ['MY_ENV_VAR']])
于 2013-04-03T22:11:27.473 回答
1

这是一个吐出当前环境的程序。

#!/usr/bin/env python
##program_name
import os
for k,v in os.environ.iteritems():
    print k, '=', v

这是一个调用另一个程序的程序,但首先改变了环境

#!/usr/bin/env python
import subprocess, os
newenv = os.environ.copy()
newenv['MY_ENV_VAR'] = 'value'
args = ['./program_name', 'arg1', 'arg2', 'etc']
proc = subprocess.Popen(args, env=newenv)
pid = proc.pid
proc.wait()
print 'PID =', pid
于 2013-04-03T22:33:43.777 回答