如何通过subprocess.Popen获取PID自定义环境变量?

时间:2013-04-03 22:02:27

标签: python subprocess popen pid

使用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”,我想因为没有shell来解释它。好的,所以我尝试了上面的内容,但改为使用这一行:

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

这很好,花花公子,除了回显的值是空白的(显然不存在)。即使它确实有效,我也会获得shell的PID,而不是我想要启动的实际过程。

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

2 个答案:

答案 0 :(得分:2)

你的上一个版本非常接近,但还不完全。

您不希望$MY_ENV_VAR成为echo的参数。 echo程序在其环境中将MY_ENV_VAR,但echo不会进行任何env变量扩展。在它到达echo之前,你需要它由shell扩展。

这实际上可能与您的真实测试用例无关。您已经 在所有测试中获取子进程的环境变量,只是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来做它的shelly时,你想要一个命令字符串。

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

另一种选择是在Python中扩展变量而不是让shell执行它。那你甚至不需要一个shell:

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

...或者,更简单:

proc = subprocess.Popen(['echo', os.environ['MY_ENV_VAR']])

答案 1 :(得分: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
相关问题