2009-07-31 27 views
14

Quiero llamar a un proceso a través de un programa python, sin embargo, este proceso necesita algunas variables de entorno específicas establecidas por otro proceso. ¿Cómo puedo obtener las primeras variables de entorno de proceso para pasarlas al segundo?Cómo obtener el entorno de un subproceso en Python

Esto es lo que ve el programa como:

import subprocess 

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

pero el procesar no comparten el mismo entorno. Tenga en cuenta que estos programas no son míos (el primero es un archivo .bat grande y feo y el segundo es un software patentado) así que no puedo modificarlos (bueno, puedo extraer todo lo que necesito del archivo .bat pero es muy combinador)

NB: Estoy utilizando Windows, pero yo prefiero una solución multiplataforma (pero mi problema no sucedería en un Unix ...)

+0

Un archivo .bat? Si está ejecutando en Windows, debería decirlo claramente. –

Respuesta

2

Puesto que usted es al parecer en Windows, necesita una Respuesta de Windows.

Cree un archivo de proceso por lotes, por ej. "Run_program.bat", y ejecutar ambos programas:

@echo off 
call proc1.bat 
proc2 

El script se ejecutará y ajustar las variables del entorno. Ambos scripts se ejecutan en el mismo intérprete (cmd.ejemplo exe), por lo que las variables prog1.bat conjuntos se ajustarse cuando se ejecuta prog2.

No es terriblemente bonito, pero funcionará.

(personas UNIX, puede hacer lo mismo en una escritura del golpe: "file.sh fuente")

+0

Estoy específicamente tratando de evitar el uso de 'sourch blah; now_do_second_thing' – nmz787

4

Como usted dice, los procesos no comparten la entorno, por lo que lo que pides literalmente no es posible, no solo en Python, sino con cualquier lenguaje de programación.

Lo que puede hacer es poner las variables de entorno en un archivo o en una tubería, y, o bien

  • tener el proceso padre las leyó, y pasarlos a Proc2 antes de crear proc2, o
  • tienen proc2 leerlos, y establecer localmente

Ésta requeriría la cooperación de proc2; el primero requiere que las variables se conozcan antes de que se inicie proc2.

+0

En Linux, si usted es un usuario root, se puede comprobar/proc//environ y analizarlo ... no es "imposible". – 0x6adb015

+0

@ 0x6abd015: sin embargo, esto no es lo que el PO se pregunta: él no quiere proc2 averiguar lo que el entorno del proc1 es (lo que puede hacer con el sistema de ficheros proc), pero él quiere proc1 a * establecido * ambiente para proc2 - Todavía reclamo que esto es imposible. –

0

El entorno se hereda del proceso principal. Establezca el entorno que necesita en el script principal, no en un subproceso (secundario).

+0

Esto no responde la pregunta. Hay buenas razones para no hacer esto también, si tiene programas que necesitan un conjunto de variables ENV en conflicto, por ejemplo. – nmz787

0

Dos cosas a la mente: (1) hacer que los procesos compartan el mismo entorno, combinándolos de alguna manera en el mismo proceso, o (2) hacer que el primer proceso produzca resultados que contengan las variables de entorno relevantes, de esa manera Python puede leerlo y construir el entorno para el segundo proceso. Creo (aunque no estoy 100% seguro) que no hay ninguna forma de obtener el medio ambiente de un subproceso como esperas hacer.

0

The Python standard module multiprocessing tienen un sistema de colas que le permite pasar el objeto pickle-able para pasar a través de los procesos. También los procesos pueden intercambiar mensajes (un objeto escabechado) utilizando os.pipe. Recuerde que los recursos (por ejemplo, la conexión de la base de datos) y el identificador (por ejemplo, identificadores de archivos) no se pueden escanear.

Usted puede encontrar este enlace interesante: Communication between processes with multiprocessing

También el PyMOTw sobre multiprocesamiento vale la pena mencionar: multiprocessing Basics

lo siento por mi ortografía

23

Aquí hay un ejemplo de cómo se puede extraer variables de entorno desde un archivo por lotes o cmd sin crear una script de envoltura. Disfrutar.

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 

Así que para responder a su pregunta, debe crear un archivo .py que hace lo siguiente:

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

Una edición sugiere que la implementación tal como está escrita no es compatible con páginas de códigos que no sean ASCII. En ese caso, la solución recomendada era colocar 'chcp 65001> NULL &&' antes de '{env_cmd}' en la construcción del cmd. –

+1

Aquí está la versión más actualizada de esta función https://github.com/PySide/pyside2-setup/blob/master/utils.py#L379 –

+0

Esto no es multiplataforma, como solicitó OP. – nmz787

Cuestiones relacionadas