如何在子流程完成运行后获取它的环境变量?

时间:2011-05-06 00:25:16

标签: python environment-variables subprocess

我正在寻找一种方法来做到这一点,以便我可以将它传递给另一个子进程的环境。

5 个答案:

答案 0 :(得分:4)

不幸的是,孩子的环境会在退出后立即消失,即使您使用/proc filesystem on Unix特殊文件/proc/[pid]/environ,它也不会反映子进程所做的更改。

即使上面确实有效,你也会遇到竞争条件:父母需要确定阅读环境的“正确时间”,理想情况是在儿童修改后。要做到这一点,父母需要与孩子协调,只要你协调,你也可以明确沟通。

您需要在父级和子级之间通过套接字,管道,共享内存等传递状态。multiprocessing module可以使这更容易,让您通过队列或管道将数据从子级传递给父级

已更新以下是使用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}

答案 1 :(得分:4)

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

它基于Fnord的版本,没有临时文件,并且有一条标记线来区分SET命令和进程本身的任何输出。它不是防弹的,但它可以用于我的目的。

#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>

int main(int argc, string argv[])
{
    if (argv[1] != NULL)
    {
        int k = atoi(argv[1]);
        if ((argc == 2) && (k >= 0))
        {
            printf("Type what you would like to encrypt!\n");  
            string text = GetString();
            for (int i = 0, n = strlen(text); i < n; i++)
            {
                if (isalpha(text[i]) || isspace(text[i]))
                {
                    if (isupper(text[i]))
                    {
                        text[i] = text[i] + k;
                        if (text[i] > 'Z')
                        {
                            text[i] = text[i] - 26;
                            printf("%c", text[i]);
                        }
                        else
                        printf("%c", text[i]);
                    }
                    else if (islower(text[i]))
                    {
                        text[i] = text[i] + k;
                        if (text[i] > 'z')
                        {
                            text[i] = text[i] - 26;
                            printf("%c", text[i]);
                        }
                        else                        
                        printf("%c", text[i]);
                    }
                    else if (isspace(text[i]))
                    {
                        printf(" ");
                        if (isupper(text[i + 1]))
                        {
                            text[i + 1] = text[i + 1] + k;
                            if (text[i + 1] > 'Z')
                            {
                                text[i + 1] = text[i + 1] - 26;
                                printf("%c", text[i + 1]);
                            }
                            else
                            printf("%c", text[i + 1]);
                        }
                        else if (islower(text[i + 1]))
                        {
                            text[i + 1] = text[i + 1] + k;
                            if (text[i + 1] > 'z')
                            {
                                text[i + 1] = text[i + 1] - 26;
                                printf("%c", text[i + 1]);
                            }
                            else
                            printf("%c", text[i + 1]);
                        }
                        i++;
                    } 
                }
                else
                printf("%c", text[i]);
            }
            printf("\n");
            return 0;
        }
        else
        printf("Usage: ./caesar <non-negative integer>\n");
        return 1;        
    }
    else 
    printf("Usage: ./caesar <non-negative integer>\n");
    return 1;    
}

答案 2 :(得分:2)

在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文件,然后使用它生成的环境变量,修改/添加它们,传递给新进程......等等......

答案 3 :(得分:1)

你能在第一个子进程中打印出来并在python中处理那个字符串吗?

答案 4 :(得分:0)

韦德的回答几乎完美。显然我的环境中有一个没有第二个元素的“'” - 这破坏了 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