Frage

Ich brauche einen Shell-Befehl asynchron von einem Python-Skript auszuführen. Damit meine ich, dass ich meine Python-Skript weiter ausgeführt werden, während der externe Befehl losgeht und tut, was es tun muss.

Ich lese diesen Beitrag:

  

Aufruf ein externes Kommando in Python

Ich ging dann weg und einige Tests tat, und es sieht aus wie os.system() wird die Arbeit zur Verfügung gestellt, dass ich & am Ende des Befehls verwenden, so dass ich muß nicht warten, bis es zurück. Was ich frage mich ist, ob dies der richtige Weg ist, so etwas zu erreichen? Ich habe versucht, commands.call() aber es wird für mich nicht funktionieren, weil es blockiert auf dem externen Befehl.

Bitte lassen Sie mich wissen, ob mit os.system() hierfür ratsam ist oder wenn ich eine andere Route versuchen sollte.

War es hilfreich?

Lösung

subprocess.Popen tut genau das, was Sie wollen.

from subprocess import Popen
p = Popen(['watch', 'ls']) # something long running
# ... do other stuff while subprocess is running
p.terminate()

(Bearbeiten die Antwort von den Kommentaren zu vervollständigen)

Die Popen Beispiel können verschiedene andere Dinge tun, wie Sie können poll() um es zu sehen, ob es noch läuft, und Sie können communicate() damit es Daten über stdin zu senden, und warten, bis es zu beenden.

Andere Tipps

Wenn Sie viele Prozesse parallel laufen zu lassen und sie dann behandeln, wenn sie Ergebnisse liefern, können Sie Abfrage wie im folgenden verwendet werden:

from subprocess import Popen, PIPE
import time

running_procs = [
    Popen(['/usr/bin/my_cmd', '-i %s' % path], stdout=PIPE, stderr=PIPE)
    for path in '/tmp/file0 /tmp/file1 /tmp/file2'.split()]

while running_procs:
    for proc in running_procs:
        retcode = proc.poll()
        if retcode is not None: # Process finished.
            running_procs.remove(proc)
            break
        else: # No process is done, wait a bit and check again.
            time.sleep(.1)
            continue

    # Here, `proc` has finished with return code `retcode`
    if retcode != 0:
        """Error handling."""
    handle_results(proc.stdout)

Der Steuerablauf gibt es ein wenig gewunden, weil ich versuche, es klein zu machen - Sie Ihren Geschmack umgestalten kann. : -)

Dies hat den Vorteil, zuerst die frühreifenden Anfragen bedient. Wenn Sie communicate auf der ersten laufenden Prozess aufrufen und stellt sich heraus, die am längsten zu laufen, werden die anderen laufenden Prozesse dort wurden sitzt Leerlauf, wenn Sie ihre Ergebnisse Handhabung werden können.

Was ich frage mich, wenn diese [os.system ()] der richtige Weg ist, so etwas zu erreichen?

Nein. os.system() ist nicht der richtige Weg. Deshalb jeder sagt subprocess zu verwenden.

Weitere Informationen finden Sie http://docs.python.org/library /os.html#os.system

  

Das Subprozess Modul bietet mehr   leistungsstarke Einrichtungen zum Laichen neuen   Prozesse und Abrufen ihrer   Ergebnisse; unter Verwendung dieses Moduls   bevorzugt, diese Funktion zu verwenden. Verwenden   die Subprozess Modul. Prüfen   vor allem der Ersatz älterer   Funktionen mit dem Subprozess-Modul   Abschnitt.

Ich habe gute Erfolge hatte mit dem asyncproc Modul , die beschäftigt sich gut mit dem Ausgang von den Prozessen. Zum Beispiel:

import os
from asynproc import Process
myProc = Process("myprogram.app")

while True:
    # check to see if process has ended
    poll = myProc.wait(os.WNOHANG)
    if poll is not None:
        break
    # print any new output
    out = myProc.read()
    if out != "":
        print out

Mit pexpect [ http://www.noah.org/wiki/Pexpect ] mit readlines non-blocking ist ein weiterer Weg, dies zu tun. Pexpect löst die Deadlock Probleme, können Sie einfach die Prozesse im Hintergrund laufen und gibt einfache Möglichkeiten, Rückrufe zu haben, wenn Ihr Prozess vordefinierten Strings ausspuckt, und in der Regel mit dem Prozess sehr viel einfacher macht die Interaktion.

Ich habe das gleiche Problem mit einem 3270-Terminal zu verbinden versucht, die s3270 Scripting Software in Python. Jetzt bin ich die Lösung von Problem mit einer Unterklasse von Verfahren, die ich hier gefunden:

http://code.activestate.com/recipes/440554/

Und hier wird die Probe aus der Datei entnommen:

def recv_some(p, t=.1, e=1, tr=5, stderr=0):
    if tr < 1:
        tr = 1
    x = time.time()+t
    y = []
    r = ''
    pr = p.recv
    if stderr:
        pr = p.recv_err
    while time.time() < x or r:
        r = pr()
        if r is None:
            if e:
                raise Exception(message)
            else:
                break
        elif r:
            y.append(r)
        else:
            time.sleep(max((x-time.time())/tr, 0))
    return ''.join(y)

def send_all(p, data):
    while len(data):
        sent = p.send(data)
        if sent is None:
            raise Exception(message)
        data = buffer(data, sent)

if __name__ == '__main__':
    if sys.platform == 'win32':
        shell, commands, tail = ('cmd', ('dir /w', 'echo HELLO WORLD'), '\r\n')
    else:
        shell, commands, tail = ('sh', ('ls', 'echo HELLO WORLD'), '\n')

    a = Popen(shell, stdin=PIPE, stdout=PIPE)
    print recv_some(a),
    for cmd in commands:
        send_all(a, cmd + tail)
        print recv_some(a),
    send_all(a, 'exit' + tail)
    print recv_some(a, e=0)
    a.wait()

In Anbetracht „Ich muss nicht warten, bis es zurückzubringen“, ist eine der einfachsten Lösungen werden diese:

subprocess.Popen( \
    [path_to_executable, arg1, arg2, ... argN],
    creationflags = subprocess.CREATE_NEW_CONSOLE,
).pid

Aber ... Von dem, was ich gelesen das ist nicht „der richtige Weg, um so etwas zu erreichen“ erstellt aufgrund von Sicherheitsrisiken durch subprocess.CREATE_NEW_CONSOLE Flagge.

Die wichtigsten Dinge, die hier passieren ist die Verwendung von subprocess.CREATE_NEW_CONSOLE neue Konsole und .pid erstellen (kehrt der Prozess-ID, so dass Sie das Programm später überprüfen können, wenn Sie wollen), so dass nicht für das Programm zu warten, um seine Arbeit zu beenden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top