子进程运行结束后如何获取其环境变量?

发布于 2024-11-05 02:43:37 字数 43 浏览 0 评论 0原文

我正在寻找一种方法来执行此操作,以便我可以将其传递到另一个子流程的环境。

I'm looking for a way to do this, so that I can pass it to the environment of another subprocess.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

倾城花音 2024-11-12 02:43:37

这是一个简单的函数,它在子进程中运行命令,然后将其环境提取到当前进程中。

它基于 Fnord 的版本,没有临时文件,并带有一个标记行来区分 SET 命令和进程本身的任何输出。它不是防弹的,但它适合我的目的。

def setenv(cmd):
    cmd = cmd + ' && echo ~~~~START_ENVIRONMENT_HERE~~~~ && set'

    env = (subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
                     .stdout
                     .read()
                     .decode('utf-8')
                     .splitlines())

    record = False
    for e in env:
        if record:
            e = e.strip().split('=')
            os.environ[e[0]] = e[1]
        elif e.strip() == '~~~~START_ENVIRONMENT_HERE~~~~': 
            record = True

Here's a simple function which runs a command in a subprocess, then extracts its environment into the current process.

It's based on Fnord's version, without the tempfile, and with a marker line to distinguish the SET command from any output of the process itself. It's not bulletproof, but it work for my purposes.

def setenv(cmd):
    cmd = cmd + ' && echo ~~~~START_ENVIRONMENT_HERE~~~~ && set'

    env = (subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
                     .stdout
                     .read()
                     .decode('utf-8')
                     .splitlines())

    record = False
    for e in env:
        if record:
            e = e.strip().split('=')
            os.environ[e[0]] = e[1]
        elif e.strip() == '~~~~START_ENVIRONMENT_HERE~~~~': 
            record = True
一场信仰旅途 2024-11-12 02:43:37

不幸的是,孩子的环境一旦退出就会消失,即使你在 Unix 上使用 /proc 文件系统 特殊文件 /proc/[pid]/environ 它不会反映子进程所做的更改。

即使上述方法确实有效,您也会遇到竞争条件:父母需要确定读取环境的“正确时间”,最好是在孩子修改环境之后立即确定。要做到这一点,父母需要与孩子协调,只要你在协调,你就可以明确地沟通。

您需要通过套接字、管道、共享内存等在父级和子级之间传递状态。 多处理模块可以使这变得更容易一些,让您可以通过队列或管道将数据从子级传递到父级。

已更新 下面是使用multiprocessing 模块让父进程与子进程共享值以及让子进程通过队列相互通信的简要概述。它使它变得非常简单:

import os
from multiprocessing import Process, Manager, Queue

def worker1(d, q):
    # receive value from worker2
    msg = q.get()
    d['value'] += 1
    d['worker1'] = os.getpid(), msg

def worker2(d, q):
    # send value to worker1
    q.put('hi from worker2')
    d['value'] += 1
    d['worker2'] = os.getpid()

if __name__ == '__main__':
    mgr = Manager()
    d = mgr.dict()
    q = Queue()
    d['value'] = 1
    p1 = Process(target=worker1, args=(d,q))
    p1.start()
    p2 = Process(target=worker2, args=(d,q))
    p2.start()
    p1.join()
    p2.join()
    print d

结果:

{'worker1': (47395, 'hi from worker2'), 'worker2': 47396, 'value': 3}

Unfortunately the child's environment will evaporate as soon as it exits, and even if you use the /proc filesystem on Unix special file /proc/[pid]/environ it won't reflect changes made by the child process.

Even if the above did work, you'd have a race condition: the parent would need to determine the "right time" to read the environment, ideally right after the child modified it. To do that the parent would need to coordinate with the child, and as long as you're coordinating you might as well be communicating explicitly.

You'd need to pass state between parent and child over a socket, pipe, shared memory, etc. The multiprocessing module can make this a bit easier, letting you pass data from child to parent via queues or pipes.

Updated Here's a quick sketch of using the multiprocessing module to let a parent process share values with child processes, and for child processes to communicate with one another across a queue. It makes it pretty simple:

import os
from multiprocessing import Process, Manager, Queue

def worker1(d, q):
    # receive value from worker2
    msg = q.get()
    d['value'] += 1
    d['worker1'] = os.getpid(), msg

def worker2(d, q):
    # send value to worker1
    q.put('hi from worker2')
    d['value'] += 1
    d['worker2'] = os.getpid()

if __name__ == '__main__':
    mgr = Manager()
    d = mgr.dict()
    q = Queue()
    d['value'] = 1
    p1 = Process(target=worker1, args=(d,q))
    p1.start()
    p2 = Process(target=worker2, args=(d,q))
    p2.start()
    p1.join()
    p2.join()
    print d

Result:

{'worker1': (47395, 'hi from worker2'), 'worker2': 47396, 'value': 3}
束缚m 2024-11-12 02:43:37

在 Windows 中,您可以使用 SET 命令来获取您想要的内容,如下所示:

import os, tempfile, subprocess

def set_env(bat_file):
    ''' Set current os.environ variables by sourcing an existing .bat file
        Note that because of a bug with stdout=subprocess.PIPE in my environment
        i use '>' to pipe out the output of 'set' into a text file, instead of
        of using stdout. So you could simplify this a bit...
    '''

    # Run the command and pipe to a tempfile
    temp = tempfile.mktemp()
    cmd = '%s && set > %s'%(bat_file,temp)
    login = subprocess.Popen(cmd, shell=True)
    state = login.wait()

    # Parse the output
    data = []
    if os.path.isfile(temp):
        with open(temp,'r') as file:
            data = file.readlines()
        os.remove(temp)

    # Every line will set an env variable
    for env in data:
        env = env.strip().split('=')
        os.environ[env[0]] = env[1]


# Make an environment variable
os.environ['SOME_AWESOME_VARIABLE']='nothing'

# Run a batch file which you expect, amongst other things, to change this env variable
set_env('C:/do_something_awesome.bat')

# Lets see what happened
os.environ['SOME_AWESOME_VARIABLE']
// RESULT: 'AWESOME'

因此,现在如果您可以使用它来读取 .bat 文件,然后根据需要使用它生成的环境变量,请修改/添加到它们,传递到新流程......等等......

In Windows you could use the SET command to get what you want, like this:

import os, tempfile, subprocess

def set_env(bat_file):
    ''' Set current os.environ variables by sourcing an existing .bat file
        Note that because of a bug with stdout=subprocess.PIPE in my environment
        i use '>' to pipe out the output of 'set' into a text file, instead of
        of using stdout. So you could simplify this a bit...
    '''

    # Run the command and pipe to a tempfile
    temp = tempfile.mktemp()
    cmd = '%s && set > %s'%(bat_file,temp)
    login = subprocess.Popen(cmd, shell=True)
    state = login.wait()

    # Parse the output
    data = []
    if os.path.isfile(temp):
        with open(temp,'r') as file:
            data = file.readlines()
        os.remove(temp)

    # Every line will set an env variable
    for env in data:
        env = env.strip().split('=')
        os.environ[env[0]] = env[1]


# Make an environment variable
os.environ['SOME_AWESOME_VARIABLE']='nothing'

# Run a batch file which you expect, amongst other things, to change this env variable
set_env('C:/do_something_awesome.bat')

# Lets see what happened
os.environ['SOME_AWESOME_VARIABLE']
// RESULT: 'AWESOME'

So now if you can use this to read .bat files and then use the environment variables it generates as you please, modify/add to them, pass on to a new process... etc...

夜光 2024-11-12 02:43:37

你能在第一个子进程中打印它们并在 python 中处理该字符串吗?

Can you print them out in the first subprocess and deal with that string in python?

旧情别恋 2024-11-12 02:43:37

韦德的回答近乎完美。显然我的环境中有一个“'”,没有第二个元素 - 这破坏了 env[0] = env[1]

def setenv(cmd):
    cmd = cmd + ' && echo ~~~~START_ENVIRONMENT_HERE~~~~ && set'

    env = (subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
                     .stdout
                     .read()
                     .decode('utf-8')
                     .splitlines())

    record = False
    for e in env:
        if record:
            e = e.strip().split('=')
            if len(e) > 1:
                os.environ[e[0]] = e[1]
        elif e.strip() == '~~~~START_ENVIRONMENT_HERE~~~~': 
            record = True

Wade's answer was nearly perfect. Apparently I had a "'" in my environment with no second element - that was breaking env[0] = env[1]

def setenv(cmd):
    cmd = cmd + ' && echo ~~~~START_ENVIRONMENT_HERE~~~~ && set'

    env = (subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
                     .stdout
                     .read()
                     .decode('utf-8')
                     .splitlines())

    record = False
    for e in env:
        if record:
            e = e.strip().split('=')
            if len(e) > 1:
                os.environ[e[0]] = e[1]
        elif e.strip() == '~~~~START_ENVIRONMENT_HERE~~~~': 
            record = True
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文