J'essaie d'obtenir une sortie d'un sous-processus, puis de donner des commandes à ce processus en fonction de la sortie précédente. Je dois le faire un nombre variable de fois, quand le programme a besoin de plus de contribution. (Je dois également pouvoir cacher l'invite de commande de sous-processus si possible). Je pensais que ce serait une tâche facile étant donné que j'ai vu ce problème discuté dans les messages de 2003 et il est presque 2012 et il semble être un besoin assez commun et semble vraiment qu'il devrait être une partie fondamentale de n'importe quel langage de programmation. Apparemment je me suis trompé et d'une manière ou d'une autre près de 9 ans plus tard, il n'y a toujours pas de manière standard d'accomplir cette tâche de manière stable, non destructive et indépendante de la plateforme!Récupération et exécution de commandes à un sous-processus python
Je ne comprends pas vraiment beaucoup sur les E/S de fichiers et la mise en mémoire tampon ou l'enfilage, donc je préférerais une solution aussi simple que possible. S'il y a un module qui accomplit ceci qui est compatible avec python 3.x, je serais très disposé à le télécharger. Je me rends compte qu'il y a plusieurs questions qui demandent fondamentalement la même chose, mais je n'ai pas encore trouvé de réponse à la tâche simple que j'essaie d'accomplir.
Voici le code que j'ai jusqu'ici basé sur une variété de sources; Cependant, je n'ai absolument aucune idée de ce qu'il faut faire ensuite. Toutes mes tentatives se sont soldées par un échec et certains ont réussi à utiliser 100% de mon CPU (pour ne rien faire) et ne pas quitter.
import subprocess
from subprocess import Popen, PIPE
p = Popen(r'C:\postgis_testing\shellcomm.bat',stdin=PIPE,stdout=PIPE,stderr=subprocess.STDOUT shell=True)
stdout,stdin = p.communicate(b'command string')
Dans le cas où ma question ne sait pas que je suis annonce le texte du fichier de lot d'échantillons que je Démontre une situation dans laquelle il est nécessaire d'envoyer plusieurs commandes à la sous-processus (si vous tapez une chaîne de commande incorrecte du programme boucles).
@echo off
:looper
set INPUT=
set /P INPUT=Type the correct command string:
if "%INPUT%" == "command string" (echo you are correct) else (goto looper)
Si quelqu'un peut m'aider je l'apprécierais beaucoup, et je suis sûr que beaucoup d'autres le feraient aussi bien!
EDIT voici le code fonctionnel utilisant le code eryksun (post suivant):
import subprocess
import threading
import time
import sys
try:
import queue
except ImportError:
import Queue as queue
def read_stdout(stdout, q, p):
it = iter(lambda: stdout.read(1), b'')
for c in it:
q.put(c)
if stdout.closed:
break
_encoding = getattr(sys.stdout, 'encoding', 'latin-1')
def get_stdout(q, encoding=_encoding):
out = []
while 1:
try:
out.append(q.get(timeout=0.2))
except queue.Empty:
break
return b''.join(out).rstrip().decode(encoding)
def printout(q):
outdata = get_stdout(q)
if outdata:
print('Output: %s' % outdata)
if __name__ == '__main__':
#setup
p = subprocess.Popen(['shellcomm.bat'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
bufsize=0, shell=True) # I put shell=True to hide prompt
q = queue.Queue()
encoding = getattr(sys.stdin, 'encoding', 'utf-8')
#for reading stdout
t = threading.Thread(target=read_stdout, args=(p.stdout, q, p))
t.daemon = True
t.start()
#command loop
while p.poll() is None:
printout(q)
cmd = input('Input: ')
cmd = (cmd + '\n').encode(encoding)
p.stdin.write(cmd)
time.sleep(0.1) # I added this to give some time to check for closure (otherwise it doesn't work)
#tear down
for n in range(4):
rc = p.poll()
if rc is not None:
break
time.sleep(0.25)
else:
p.terminate()
rc = p.poll()
if rc is None:
rc = 1
printout(q)
print('Return Code: %d' % rc)
Toutefois, lorsque le script est exécuté à partir d'une invite de commande suivantes se produit:
C:\Users\username>python C:\postgis_testing\shellcomm7.py
Input: sth
Traceback (most recent call last):
File "C:\postgis_testing\shellcomm7.py", line 51, in <module>
p.stdin.write(cmd)
IOError: [Errno 22] Invalid argument
Il semble que le Le programme se ferme lorsqu'il est exécuté à partir de l'invite de commande. des idées?
Merci beaucoup pour cela, il fonctionne parfaitement dans oisives, mais quand je lance le code modifié (voir mon modifier dans mon message original) il me donne l'erreur suivante C: \ Users \ nom d'utilisateur> python C : \ postgis_testing \ shellcomm7.py entrée: STH retraçage (appel le plus récent en dernier): fichier "C: \ postgis_testing \ shellcomm7.py", ligne 51, dans p.stdin.write (cmd) IOError: [Errno 22] Argument invalide Il semble que le programme se ferme lorsqu'il est exécuté à partir de l'invite de commande. des idées? –
THX1138
@ THX1138: J'ai modifié la boucle pour interroger le processus et vérifier stdin avant de demander une entrée. Il casse si le processus s'est terminé. J'ai également supprimé l'objet de processus des arguments 'read_stdout'; il a été laissé par erreur de ma première ébauche. – eryksun
Lorsque j'exécute le nouveau code à partir d'une invite de commande, j'obtiens l'erreur: C: \ Utilisateurs \ nom d'utilisateur> python C: \ postgis_testing \ shellcomm8.py Traceback (appel le plus récent en dernier): Fichier "C: \ postgis_testing \ shellcomm8.py "à la ligne 38, dans bufsize = 0) fichier "C: \ Python32 \ lib \ subprocess.py", à la ligne 741, en __init__ restore_signals, start_new_session) fichier" C: \ Python32 \ lib \ subprocess.py ", ligne 960, dans _execute_child startupinfo) WindowsError: [Erreur 2] Le système ne trouve pas le fichier spécifié –
THX1138