如何从子进程获取环境变量?

27 投票
9 回答
18722 浏览
提问于 2025-04-15 13:18

我想通过一个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”。)

撰写回答