【问题标题】:How to get the environment variables of a subprocess after it finishes running?子进程完成运行后如何获取其环境变量?
【发布时间】:2011-08-19 19:40:35
【问题描述】:

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

【问题讨论】:

  • 我相信这取决于外壳。
  • 顺便谢谢大家的帮助。

标签: python environment-variables subprocess


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    不幸的是,子进程的环境一退出就会消失,即使您使用/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}
    

    【讨论】:

    • 嗨,我不需要在父子之间交换环境,而是在子进程之间交换环境。
    • 尝试获取进程环境的限制仍然适用。我已经用使用多处理模块让 2 个孩子相互交流并与父母共享数据的快速草图更新了我的答案。希望对您有所帮助。
    【解决方案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 文件,然后根据需要使用它生成的环境变量,修改/添加它们,传递给新进程...等等...

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 是的,但是有没有更漂亮的方法可以让我不必从 env 中解析脚本?
      • 好吧,我最终这样做了。似乎是最直接的方法......
      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 2020-12-22
        • 1970-01-01
        • 2021-12-07
        • 2017-06-06
        • 2022-01-22
        • 2020-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多