2009-07-31 11 views
14

Chcę wywołać proces za pomocą programu Pythona, jednak proces ten wymaga pewnych określonych zmiennych środowiskowych, które są ustawione przez inny proces. Jak mogę uzyskać pierwsze zmienne środowiskowe procesu, aby przekazać je do drugiego?Jak uzyskać środowisko z podprocesu w Pythonie

To właśnie program wyglądałby następująco:

import subprocess 

subprocess.call(['proc1']) # this set env. variables for proc2 
subprocess.call(['proc2']) # this must have env. variables set by proc1 to work 

ale przetwarzanie nie podzielają tego samego środowiska. Zauważ, że te programy nie są moje (pierwszy to duży i brzydki plik .bat, a drugi zastrzeżony soft), więc nie mogę ich zmodyfikować (ok, mogę wyodrębnić wszystko, czego potrzebuję z .bat, ale jest bardzo uciążliwy).

NB: Używam Windows, ale wolę rozwiązania wieloplatformowe (ale mój problem nie stanie na Unix-like ...)

+0

pliku .bat? Jeśli korzystasz z systemu Windows, powinieneś tak wyraźnie powiedzieć. –

Odpowiedz

2

Skoro jesteś widocznie w systemie Windows, potrzebny jest Odpowiedź systemu Windows.

Utwórz plik wsadowy opakowania, np. "run_program.bat" i uruchom oba programy:

@echo off 
call proc1.bat 
proc2 

Skrypt uruchomi się i ustawi zmienne środowiskowe. Oba skrypty działają w tym samym tłumaczu (cmd.przykład exe), więc zmienne prog1.bat ustawia będzie ustawione na po uruchomieniu prog2.

Niezbyt ładna, ale zadziała.

(Unix ludzie, można zrobić to samo w skrypcie bash. „Źródło file.sh”)

+0

Dokładam wszelkich starań, aby obejść się przy użyciu "blaszecznika"; now_do_second_thing' – nmz787

4

jak mówisz, procesy nie podzielam środowisko - więc to, czego dosłownie pytasz, nie jest możliwe, nie tylko w Pythonie, ale w dowolnym języku programowania.

Co może zrobić, to umieścić zmienne środowiskowe w pliku, lub w rurze, i albo

  • mieć proces nadrzędny je przeczytać i przekazać je do PROC2 przed utworzeniem PROC2, lub
  • mieć PROC2 je odczytać i ustawić je lokalnie

Ten ostatni wymaga współpracy z PROC2; ta pierwsza wymaga, aby zmienne stały się znane przed uruchomieniem proc2.

+0

Pod Linuksem, jeśli jesteś rootem, możesz sprawdzić/proc//environ i przeanalizować go ... nie "niemożliwe". – 0x6adb015

+0

@ 0x6abd015: jednak to nie jest to, co OP prosi: nie chce, aby proc2 dowiedział się, jakie jest środowisko proc1 (co możesz zrobić z systemem plików proc), ale chce proc1, aby * ustawiło * środowisko dla proc2 - Nadal twierdzę, że to niemożliwe. –

0

Środowisko jest dziedziczone po procesie nadrzędnym. Ustaw środowisko, którego potrzebujesz w głównym skrypcie, a nie podprocesie (potomnym).

+0

To nie odpowiada na pytanie. Istnieją również uzasadnione powody, aby tego dokonać, jeśli na przykład masz programy, które wymagają konfliktu zestawów ENV vars. – nmz787

0

Dwie rzeczy przychodzą na myśl: (1) sprawiają, że procesy dzielą to samo środowisko, łącząc je w jakiś sposób w ten sam proces, lub (2) pierwszy proces produkuje dane wyjściowe zawierające odpowiednie zmienne środowiskowe, w ten sposób Python może go przeczytać i skonstruować środowisko dla drugiego procesu. Myślę, że (chociaż nie jestem w 100% pewny), że nie ma sposobu na uzyskanie środowiska z podprocesu, tak jak planujesz.

0

The Python standard module multiprocessing mają system kolejki, który pozwala przekazywać obiekty pickle stanie się przekazywane przez procesy. Również procesy mogą wymieniać komunikaty (obiekt wytrawiony) za pomocą os.pipe. Pamiętaj, że zasoby (np. Połączenie z bazą danych) i uchwyt (np. Uchwyty plików) nie mogą być wytrawiane.

Można znaleźć ten link za interesujący: Communication between processes with multiprocessing

Również PyMOTw o wieloprocesorowe warto wspomnieć: multiprocessing Basics

przepraszam za moją ortografią

23

Oto przykład, w jaki sposób można wyodrębnić zmienne środowiskowe z pliku wsadowego lub cmd bez tworzenia skrypt otoki. Cieszyć się.

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 

Tak, aby odpowiedzieć na to pytanie, należy utworzyć plik .py, który wykonuje następujące czynności:

env = get_environment_from_batch_command('proc1') 
subprocess.Popen('proc2', env=env) 
+0

Edycja sugerowała, że ​​implementacja w formie pisemnej nie obsługuje stron kodowych spoza ASCII. W takim przypadku zalecaną poprawką było umieszczenie 'chcp 65001> NULL &&' before '{env_cmd}' w konstrukcji cmd. –

+1

Oto bardziej zaktualizowana wersja tej funkcji https://github.com/PySide/pyside2-setup/blob/master/utils.py#L379 –

+0

Nie jest to platforma wieloplatformowa, zgodnie z żądaniem OP. – nmz787