Как получить среду из подпроцесса? - PullRequest
19 голосов
/ 31 июля 2009

Я хочу вызвать процесс с помощью программы на 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

но процесс не использует ту же среду. Обратите внимание, что эти программы не мои (первая - большой и некрасивый файл .bat, а вторая - проприетарный софт), поэтому я не могу изменить их (хорошо, я могу извлечь все, что мне нужно, из .bat, но это очень удобно. ).

N.B .: Я использую Windows, но я предпочитаю кроссплатформенное решение (но моя проблема не возникнет на Unix-подобных ...)

Ответы [ 6 ]

26 голосов
/ 06 февраля 2010

Вот пример того, как вы можете извлечь переменные окружения из пакетного или 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

Таким образом, чтобы ответить на ваш вопрос, вы должны создать файл .py, который выполняет следующие действия:

env = get_environment_from_batch_command('proc1')
subprocess.Popen('proc2', env=env)
5 голосов
/ 31 июля 2009

Как вы говорите, процессы не разделяют среду - поэтому то, что вы буквально просите, невозможно, не только в Python, но и с любым языком программирования.

Что вы можете сделать, это поместить переменные окружения в файл или в канал и либо

  • попросите родительский процесс прочитать их и передать их в proc2 до создания proc2, или
  • proc2 прочитал их и установил локально

Последнее потребует сотрудничества с proc2; первый требует, чтобы переменные стали известны до запуска proc2.

2 голосов
/ 01 августа 2009

Поскольку вы, очевидно, находитесь в Windows, вам нужен ответ Windows.

Создание командного файла оболочки, например. "run_program.bat" и запустите обе программы:

@echo off
call proc1.bat
proc2

Скрипт запустится и установит свои переменные окружения. Оба сценария выполняются в одном и том же интерпретаторе (экземпляр cmd.exe), поэтому переменные prog1.bat, устанавливающие , будут установлены при выполнении prog2.

Не очень красиво, но это сработает.

(Люди из Unix, вы можете сделать то же самое в скрипте bash: "source file.sh".)

0 голосов
/ 01 августа 2009

Мультипроцессорная обработка стандартного модуля Python имеет систему очередей, которая позволяет передавать объект, способный к засолке, для прохождения через процессы. Также процессы могут обмениваться сообщениями (маринованный объект), используя os.pipe. Помните, что ресурсы (например, соединение с базой данных) и дескриптор (например, дескрипторы файлов) не могут быть выбраны.

Вы можете найти эту ссылку интересной: Связь между процессами с многопроцессорностью

Также стоит упомянуть PyMOTw о многопроцессорности: Основы многопроцессорной обработки

извините за орфографию

0 голосов
/ 31 июля 2009

На ум приходят две вещи: (1) заставить процессы совместно использовать одну и ту же среду, объединяя их каким-то образом в один и тот же процесс, или (2) сделать, чтобы первый процесс выдал выходные данные, которые содержат соответствующие переменные среды, таким образом Python прочитайте его и создайте среду для второго процесса. Я думаю (хотя я не уверен на 100%), что нет никакого способа получить среду из подпроцесса, как вы надеетесь сделать.

0 голосов
/ 31 июля 2009

Среда наследуется от родительского процесса. Задайте необходимую среду в основном скрипте, а не в подпроцессе (дочернем).

...