如何从子进程获取环境?

19 python windows subprocess environment-variables popen

我想通过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
Run Code Online (Sandbox Code Playgroud)

但是进程不共享相同的环境.请注意,这些程序不是我的(第一个是大而丑陋的.bat文件,第二个是专有软件)所以我无法修改它们(好吧,我可以从.bat中提取我需要的所有东西,但它非常简洁).

注意:我使用的是Windows,但我更喜欢跨平台的解决方案(但我的问题不会发生在类似Unix的问题上......)

Jas*_*mbs 27

下面是如何在不创建包装器脚本的情况下从批处理或cmd文件中提取环境变量的示例.请享用.

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
Run Code Online (Sandbox Code Playgroud)

因此,要回答您的问题,您将创建一个执行以下操作的.py文件:

env = get_environment_from_batch_command('proc1')
subprocess.Popen('proc2', env=env)
Run Code Online (Sandbox Code Playgroud)

  • 正如OP所要求的那样,这不是跨平台的。 (3认同)
  • 没错,通常不可能从正在运行的进程中提取环境,如 Martin v. Löwis 的回答所示。这个答案侧重于 OP 手头的问题。据推测,如果您在该平台上有“cmd.exe”,这将可以跨平台工作,如果您正在使用 proc1 的批处理文件,您会这样做。 (2认同)

Mar*_*wis 5

正如你所说,进程不会共享环境 - 所以你真正要求的是不可能的,不仅在Python中,而且在任何编程语言中.

可以做的是将环境变量放在文件或管道中,或者

  • 让父进程读取它们,并在创建proc2之前将它们传递给proc2,或者
  • proc2读取它们,并在本地设置它们

后者需要proc2的合作; 前者要求在proc2启动之前变量已知.


Gle*_*ard 2

由于您显然使用的是 Windows,因此您需要 Windows 答案。

创建一个包装批处理文件,例如 “run_program.bat”,并运行这两个程序:

@echo off
call proc1.bat
proc2
Run Code Online (Sandbox Code Playgroud)

该脚本将运行并设置其环境变量。两个脚本都在同一个解释器(cmd.exe 实例)中运行,因此prog2 执行时设置变量 prog1.bat 设置。

不是很漂亮,但它会起作用。

(Unix 用户,您可以在 bash 脚本中执行相同的操作:“source file.sh”。)