2009-07-31 5 views
14

Voglio chiamare un processo tramite un programma python, tuttavia, questo processo richiede alcune variabili d'ambiente specifiche impostate da un altro processo. Come posso ottenere le prime variabili di ambiente di processo per passarle al secondo?Come ottenere l'ambiente da un sottoprocesso in Python

Questo è ciò che il programma assomigliare:

import subprocess 

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

ma il di elaborare non condividono lo stesso ambiente. Nota che questi programmi non sono miei (il primo è grosso e brutto .bat e il secondo un soft proprietario) quindi non posso modificarli (ok, posso estrarre tutto ciò che mi serve dal .bat ma è molto combattivo).

NB: Sto usando Windows, ma io preferisco una soluzione cross-platform (ma il mio problema non sarebbe accaduto su un Unix-like ...)

+0

Un file .bat? Se stai usando Windows, dovresti dirlo chiaramente. –

risposta

2

Visto che siete a quanto pare in Windows, è necessario un Risposta di Windows.

Creare un file batch wrapper, ad es. "Run_program.bat", ed eseguire entrambi i programmi:

@echo off 
call proc1.bat 
proc2 

Lo script verrà eseguito e impostare le sue variabili d'ambiente. Entrambi gli script vengono eseguiti nello stesso interprete (cmd.exe istanza), quindi le variabili prog1.bat impostate saranno impostate su quando viene eseguito prog2.

Non molto bello, ma funzionerà.

(persone Unix, si può fare la stessa cosa in uno script bash:. "Fonte file.sh")

+0

Sto specificatamente cercando di aggirare usando 'sourch blah; now_do_second_thing' – nmz787

4

Come dici tu, i processi non condividono la ambiente - quindi quello che chiedi letteralmente non è possibile, non solo in Python, ma con qualsiasi linguaggio di programmazione.

Quello che può fare è di mettere le variabili di ambiente in un file, o in un tubo, e sia

  • avere il processo padre li legge, e passarli al Proc2 prima della creazione proc2, o
  • hanno proc2 leggerli, e li localmente

quest'ultimo avrebbe richiesto la collaborazione di proc2; il primo richiede che le variabili diventino note prima dell'avvio di proc2.

+0

Sotto Linux, se si è root, è possibile controllare/proc//environ e analizzarlo ... non "impossibile". – 0x6adb015

+0

@ 0x6abd015: tuttavia, questo non è ciò che l'OP chiede: non vuole che proc2 trovi l'ambiente di proc1 (cosa si può fare con il file system proc), ma vuole proc1 a * set * environment per proc2 - Continuo a sostenere che questo è impossibile. –

0

L'ambiente è ereditato dal processo padre. Imposta l'ambiente che ti serve nello script principale, non un sottoprocesso (figlio).

+0

Questo non risponde alla domanda. Ci sono buone ragioni per non farlo anche se, ad esempio, hai programmi che necessitano di set di vere ENV in conflitto. – nmz787

0

Mi vengono in mente due cose: (1) rendere i processi condividono lo stesso ambiente, combinandoli in qualche modo nello stesso processo, oppure (2) hanno il primo processo che produce output che contiene le variabili di ambiente rilevanti, in questo modo Python può leggerlo e costruire l'ambiente per il secondo processo. Penso (anche se non sono sicuro al 100%) che non ci sia modo di ottenere l'ambiente da un sottoprocesso come speri di fare.

0

The Python standard module multiprocessing dispone di un sistema di code che consente di passare l'oggetto pickle-able da passare attraverso i processi. Anche i processi possono scambiare messaggi (un oggetto decapitato) usando os.pipe. Ricorda che le risorse (ad es. La connessione al database) e l'handle (ad esempio handle di file) non possono essere decapitati.

Si possono trovare questo link interessante: Communication between processes with multiprocessing

Anche il PyMOTw circa multiprocessing vale la pena menzionare: multiprocessing Basics

dispiace per la mia ortografia

23

Ecco un esempio di come è possibile estrarre le variabili di ambiente da un file batch o cmd senza creare un script wrapper. Godere.

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 

Quindi, per rispondere alla tua domanda, si potrebbe creare un file .py che fa la seguente:

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

Una modifica suggeriva che l'implementazione come scritta non supporta le code page non ASCII. In quel caso, la soluzione consigliata era posizionare 'chcp 65001> NULL &&' prima di '{env_cmd}' nella costruzione di cmd. –

+1

Ecco la versione più aggiornata di questa funzione https://github.com/PySide/pyside2-setup/blob/master/utils.py#L379 –

+0

Non è multipiattaforma, come richiesto dall'OP. – nmz787