簡體   English   中英

子進程運行完成后如何獲取其環境變量?

[英]How to get the environment variables of a subprocess after it finishes running?

我正在尋找一種方法來做到這一點,以便我可以將它傳遞給另一個子進程的環境。

這是一個簡單的函數,它在子進程中運行命令,然后將其環境提取到當前進程中。

它基於 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

不幸的是,子進程一旦退出,它的環境就會消失,即使您在 Unix特殊文件/proc/[pid]/environ使用/proc 文件系統,它也不會反映子進程所做的更改。

即使上述方法確實有效,您也會遇到競爭條件:父母需要確定閱讀環境的“正確時間”,最好是在孩子修改環境之后。 要做到這一點,父母需要與孩子協調,只要你在協調,你就可以明確地溝通。

您需要通過套接字、管道、共享內存等在父級和子級之間傳遞狀態。多處理模塊可以使這更容易一些,讓您可以通過隊列或管道將數據從子級傳遞到父級。

更新這是使用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}

在 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 文件,然后根據需要使用它生成的環境變量,請修改/添加到它們,傳遞給一個新進程......等等......

你能在第一個子進程中打印出來並在 python 中處理那個字符串嗎?

韋德的回答近乎完美。 顯然我的環境中有一個 "'" 沒有第二個元素 - 這破壞了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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM