如何从子进程获取环境变量?
我想通过一个Python程序来调用一个进程,但是这个进程需要一些特定的环境变量,而这些变量是由另一个进程设置的。我该如何获取第一个进程的环境变量,然后把它们传递给第二个进程呢?
这就是我的程序的样子:
import subprocess
subprocess.call(['proc1']) # this set env. variables for proc2
subprocess.call(['proc2']) # this must have env. variables set by proc1 to work
不过这两个进程并不共享同样的环境。需要注意的是,这些程序不是我写的(第一个是一个又大又复杂的.bat文件,第二个是一个专有软件),所以我不能修改它们(当然,我可以从.bat文件中提取我需要的所有内容,但这非常麻烦)。
另外,我使用的是Windows,但我更希望有一个跨平台的解决方案(不过在类Unix系统上,我的问题不会出现……)
相关问题:
9 个回答
5
正如你所说,进程之间是不能共享环境的。所以你问的这个问题,不仅在Python中不可能,在任何编程语言中都是不行的。
不过,你可以做的是把环境变量放在一个文件里,或者放在一个管道中,然后可以选择:
- 让父进程读取这些变量,并在创建proc2之前把它们传递给proc2,或者
- 让proc2自己读取这些变量,并在本地设置它们。
后者需要proc2的配合;前者则要求在启动proc2之前,这些变量就已经被知道了。
31
这里有一个例子,教你如何从批处理文件或命令文件中提取环境变量,而不需要创建一个额外的脚本。希望你喜欢。
from __future__ import print_function
import sys
import subprocess
import itertools
def validate_pair(ob):
try:
if not (len(ob) == 2):
print("Unexpected result:", ob, file=sys.stderr)
raise ValueError
except:
return False
return True
def consume(iter):
try:
while True: next(iter)
except StopIteration:
pass
def get_environment_from_batch_command(env_cmd, initial=None):
"""
Take a command (either a single command or list of arguments)
and return the environment created after running that command.
Note that if the command must be a batch file or .cmd file, or the
changes to the environment will not be captured.
If initial is supplied, it is used as the initial environment passed
to the child process.
"""
if not isinstance(env_cmd, (list, tuple)):
env_cmd = [env_cmd]
# construct the command that will alter the environment
env_cmd = subprocess.list2cmdline(env_cmd)
# create a tag so we can tell in the output when the proc is done
tag = 'Done running command'
# construct a cmd.exe command to do accomplish this
cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars())
# launch the process
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial)
# parse the output sent to stdout
lines = proc.stdout
# consume whatever output occurs until the tag is reached
consume(itertools.takewhile(lambda l: tag not in l, lines))
# define a way to handle each KEY=VALUE line
handle_line = lambda l: l.rstrip().split('=',1)
# parse key/values into pairs
pairs = map(handle_line, lines)
# make sure the pairs are valid
valid_pairs = filter(validate_pair, pairs)
# construct a dictionary of the pairs
result = dict(valid_pairs)
# let the process finish
proc.communicate()
return result
所以,针对你的问题,你需要创建一个 .py 文件,里面包含以下内容:
env = get_environment_from_batch_command('proc1')
subprocess.Popen('proc2', env=env)
2
因为你显然是在用Windows,所以我们来讲讲Windows的解决办法。
你可以创建一个批处理文件,比如叫“run_program.bat”,然后在里面运行两个程序:
@echo off
call proc1.bat
proc2
这个脚本会运行并设置它的环境变量。两个脚本会在同一个解释器里运行(也就是同一个cmd.exe实例),所以当执行prog2的时候,prog1.bat设置的变量会生效。
虽然看起来不太美观,但这样是可以工作的。
(如果你是Unix用户,可以在bash脚本里做同样的事情:使用“source file.sh”。)