Domanda

Voglio chiamare un processo tramite un programma Python, tuttavia, questo processo ha bisogno di alcune variabili d'ambiente specifiche che sono impostate da un altro processo. Come posso ottenere le prime variabili di ambiente di processo per passarle alla seconda?

Ecco come appare il programma:

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 processo to non condivide lo stesso ambiente. Si noti che questi programmi non sono miei (il primo è un file .bat grande e brutto e il secondo un software proprietario) quindi non posso modificarli (ok, posso estrarre tutto ciò di cui ho bisogno dal .bat ma è molto complicato ).

N.B .: Sto usando Windows, ma preferisco una soluzione multipiattaforma (ma il mio problema non si verificherebbe su un sistema Unix ...)

È stato utile?

Soluzione

Dal momento che apparentemente sei su Windows, hai bisogno di una risposta di Windows.

Crea un file batch wrapper, ad es. " run_program.bat " ;, ed esegui entrambi i programmi:

@echo off
call proc1.bat
proc2

Lo script verrà eseguito e imposterà le sue variabili di ambiente. Entrambi gli script vengono eseguiti nello stesso interprete (istanza cmd.exe), quindi le variabili prog1.bat set verranno impostate quando prog2 viene eseguito.

Non terribilmente carino, ma funzionerà.

(Unix gente, potete fare la stessa cosa in uno script bash: " source file.sh " ;.)

Altri suggerimenti

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

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, dovresti creare un file .py che procede come segue:

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

Come dici tu, i processi non condividono l'ambiente, quindi ciò che chiedi letteralmente non è possibile, non solo in Python, ma con qualsiasi linguaggio di programmazione.

Quello che puoi è mettere le variabili d'ambiente in un file, o in una pipe, e

  • chiedi al processo genitore di leggerli e passali a proc2 prima della creazione di proc2, oppure
  • li proc2 li legge e li imposta localmente

Quest'ultimo richiederebbe la cooperazione di proc2; il primo richiede che le variabili vengano rese note prima dell'avvio di proc2.

Mi vengono in mente due cose: (1) fare in modo che i processi condividano lo stesso ambiente, combinandoli in qualche modo nello stesso processo o (2) fare in modo che il primo processo produca output che contenga le variabili di ambiente rilevanti, in questo modo Python può leggilo e costruisci l'ambiente per il secondo processo. Penso (anche se non sono sicuro al 100%) che non c'è modo di ottenere l'ambiente da un sottoprocesso come speri di fare.

Il multiprocessing del modulo standard Python ha un sistema di code che ti consente di passare il pickle oggetto in grado di essere passato attraverso i processi. Inoltre i processi possono scambiare messaggi (un oggetto in salamoia) usando os.pipe. Ricorda che le risorse (ad esempio: connessione al database) e handle (ad esempio: handle di file) non possono essere decapate.

Questo link potrebbe essere interessante: Comunicazione tra processi con multiprocessing

Anche il PyMOTw sul multiprocessing merita di essere menzionato: Nozioni di base sul multiprocessing

scusami per l'ortografia

L'ambiente è ereditato dal processo parent. Imposta l'ambiente di cui hai bisogno nello script principale, non un sottoprocesso (figlio).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top