Comment puis-je utiliser des sous-processus.Popen de connecter plusieurs processus par des tuyaux?
Comment puis-je exécuter la commande shell suivante à l'aide de l'Python sous-processus
module?
echo "input data" | awk -f script.awk | sort > outfile.txt
Les données d'entrée viendra à partir d'une chaîne, donc je n'ai pas réellement besoin echo
. J'ai de loin, quelqu'un peut-il expliquer comment j'arrive à pipe à travers sort
trop?
p_awk = subprocess.Popen(["awk","-f","script.awk"],
stdin=subprocess.PIPE,
stdout=file("outfile.txt", "w"))
p_awk.communicate( "input data" )
Mise à JOUR: Note que, bien que l'on a accepté la réponse ci-dessous n'est pas réellement répondre à la question posée, je crois que S. Lott est droit et qu'il vaut mieux éviter d'avoir à résoudre le problème en premier lieu!
Vous devez vous connecter pour publier un commentaire.
Vous seriez un peu plus heureux avec le suivant.
Déléguer une partie du travail à la coque. Laissez connecter deux processus avec un pipeline.
Tu serais beaucoup plus heureux de réécriture 'script.awk' en Python, en éliminant awk et le pipeline.
Modifier. Parmi les raisons qui expliquent ce qui suggère que awk n'aide pas.
[Il y a trop de raisons de réagir via les commentaires.]
Awk est l'ajout d'une étape d'aucune valeur significative. Il n'y a rien d'unique à propos de awk traitement que Python n'a pas de poignée.
Le pipelining de awk pour trier, pour les grands ensembles de données, peut améliorer écoulé, les temps de traitement. Pour de courtes séries de données, il n'a pas d'avantage significatif. Un rapide de mesure de
awk >file ; sort file
etawk | sort
révélera de simultanéité de l'aide. Avec le tri, il est rarement utile parce que le tri n'est pas une fois par le filtre.La simplicité de "Python pour trier" en cours de traitement (au lieu de "Python de awk pour trier") empêche exactement le type de questions posées ici.
Python -- alors que wordier que awk-est également explicite où awk a certaines règles implicites qui sont opaques pour les débutants, et source de confusion pour les non-spécialistes.
Awk (comme le script shell lui-même) ajoute Encore un Autre langage de Programmation. Si tout cela peut être fait en une seule langue (Python), l'élimination de la coquille et de la awk programming élimine les deux langages de programmation, permettant à quelqu'un de se focaliser sur la valeur à la production de pièces de la tâche.
Ligne du bas: awk ne pouvez pas ajouter une valeur significative. Dans ce cas, awk est un coût net; il ajouté assez de complexité qu'il était nécessaire de poser cette question. Retrait de awk sera un gain net.
Barre latérale Pourquoi la construction d'un pipeline (
a | b
) est tellement dur.Lorsque la coquille est confronté à
a | b
il a à faire ce qui suit.Fourche d'un processus enfant de l'original coque. Cela finira par devenir b.
Construire un os de la pipe. (pas un Python sous-processus.PIPE), mais l'appel
os.pipe()
qui renvoie deux nouveaux descripteurs de fichiers qui sont connectés via la commune du tampon. À ce stade, le processus a stdin, stdout, stderr de son parent, en plus d'un fichier qui sera "a stdout" et "b stdin".Fourche d'un enfant. L'enfant remplace le stdout avec la nouvelle de la sortie standard (stdout). Exec le
a
processus.Le b enfant ferme remplace son entrée standard avec le nouveau b stdin. Exec le
b
processus.Le b enfant attend pour un de complet.
Le parent est en attente pour b pour valider.
Je pense que le ci-dessus peut être utilisé de manière récursive pour frayer
a | b | c
, mais vous devez implicitement parenthesize long des pipelines, en les traitant comme s'ilsa | (b | c)
.Depuis Python a
os.pipe()
,os.exec()
etos.fork()
, et vous pouvez remplacersys.stdin
etsys.stdout
, il y a un moyen de le faire ci-dessus en pur Python. En effet, vous pourriez être en mesure de travailler sur certains raccourcis à l'aide deos.pipe()
etsubprocess.Popen
.Cependant, il est plus facile de déléguer cette opération à la coquille.
-c
est déjà inclus dansshell=True
.pipes.quote()
peut briser parfois. Vous pouvez essayer deplumbum
module qui intègre la LIS en Python, voir exemple dans mon asnwer-c
crée un deuxième shell. Vous êtes mieux avecPopen('pipe|line', shell=True)
plutôt que la, franchement, plutôt lunatique,Popen(['-c', 'pipe|line'], shell=True)
./bin/sh -c -c 'awk ...'
de commande.p1.wait()
dans votre code.p1.communicate()
récolte le processus de l'enfant.shell=True
aussi découragé dans le sous-processus de documentation. Je ne vois pas la raison pourquoi les gens jusqu'-voté @S. Lott réponse.plumbum
(la syntaxe shell intégré en Python) ou un autre module qui accepte une syntaxe similaire (dans une chaîne de caractères) et construit le pipeline pour vous (même comportement quel que soit local/bin/sh
n').Pour émuler un oléoduc de shell:
sans invoquer le shell (voir 17.1.4.2. Remplacement d'oléoduc de shell):
plumbum
fournit certains de la syntaxe de sucre:Analogique de:
est:
pipes.quote()
) ou d'introduire des bugs lors de l'exécution de la canalisation en Python, mêmea | b
pourraient être mises en œuvre avec des erreurs.http://www.python.org/doc/2.5.2/lib/node535.html couvert ce assez bien. Est-il une partie de ce que vous ne compreniez pas?
Votre programme devrait être assez similaire, mais la deuxième
Popen
aurait stdout= à un fichier, vous n'avez pas besoin de la sortie de son.communicate()
.Inspiré par @Cristian réponse. J'ai rencontré juste le même problème, mais avec une autre commande. Donc, je suis en train de mettre mes testé exemple, qui je crois pourrait être utile:
Ce qui est testé.
Ce qui a été fait
grep
exécution avec stdin de la conduite. Cette commande sera exécutée aups
exécution de la commande lors de la conduite sera rempli avec le stdout deps
.ps
avec stdout dirigé vers le canal utilisé par legrep
commande.J'aime cette façon parce qu'il est naturel de tuyau de conception délicatement enveloppé avec
subprocess
interfaces.ps_proc.wait()
aprèsgrep_proc.communicate()
.err
est toujoursNone
, sauf si vous définissezstderr=subprocess.PIPE
.Accepté la réponse est esquiver la question.
voici un extrait de code que les chaînes de la sortie de plusieurs processus:
Notez qu'il imprime également le (un peu l'équivalent d'un shell de commande de sorte que vous pouvez l'exécuter et assurez-vous que la sortie est correcte.
EDIT:
pipes
est disponible sur Windows, mais, surtout, ne semble pas réellement travail sur Windows. Voir les commentaires ci-dessous.Le Python standard library inclut désormais la
pipes
module de gestion de l':https://docs.python.org/2/library/pipes.html, https://docs.python.org/3.4/library/pipes.html
Je ne suis pas sûr combien de temps ce module a été autour, mais cette approche semble être considérablement plus simple que de coucher avec
subprocess
.pipes
existaient bien avantsubprocess
module. Il construit une (*nix) oléoduc de shell (une chaîne de caractères avec"|"
qui est exécuté dans/bin/sh
). Il n'est pas portable. Ce n'est pas une alternative àsubprocess
module qui est portable et ne nécessite pas de lancer un interpréteur de commandes pour exécuter une commande.pipes
interface est à partir du moment où les Enterprise JavaBeans étaient brillants de nouvelles choses (c'est pas un compliment). Pourriez-vous fournirpipes
exemple de code qui est "très simple" que les sous-processus':check_call('echo "input data" | a | b > outfile.txt', shell=True)
dans ma réponse?check_call
commande en être de même des non-portable? DOS fournit standard (c'est à dire des *NIX-comparables, au moins autant que je sache)|
comportement, de sorte que les systèmes qui vous attendpipes
de ne pas travailler? J'avoue que l'utilisation decheck_call
avec une chaîne de caractères représentant de votre commande shell est sans doute tout aussi simple que l'utilisation depipes
, mais je m'attendais à quelque chose qui serait de faciliter la programmation de la construction d'un pipeline plutôt que de simplement prendre une seule chaîne à transmettre à la coquille (la votre d'autres exemples).plumbum
n'a l'air sympa--il semble fournir exactement la simplicité, la flexibilité et la puissance que je recherche. Toutefois, la syntaxe est entièrement opaque et non Pythonic. Donc, ce que je veux, c'est quelque chose qui est environ aussi simple et facile que standard *NIX-shell pipes (si peut-être un peu moins concis), tandis que toujours un point de vue syntaxique et stylistique "recherche" comme le Python.pipes
, à première vue, semble répondre à ces exigences; si, toutefois, vous avez raison, c'est non portable (que vous êtes probablement), c'est le moins que l'option attrayante.echo hello world
avecC:\cygwin\bin\tr a-z A-Z
échoue sur Windows, même siecho hello world | C:\cygwin\bin\tr.exe a-z A-Z
œuvres. C'est...étrange et décevant.Les réponses précédentes manqué un point important. Remplacement d'oléoduc de shell est fondamentalement correcte, comme l'a souligné geocar. Il est presque suffisant pour exécuter
communicate
sur le dernier élément de la pipe.Le problème restant est le passage du données d'entrée pour le pipeline. Avec plusieurs sous-processus, une simple
communicate(input_data)
sur le dernier élément ne fonctionne pas - il se bloque toujours. Vous devez créer un pipeline et d'un enfant manuellement comme ceci:Maintenant l'enfant fournit une entrée dans le tuyau, et le parent appels communiquer(), qui fonctionne comme prévu. Avec cette approche, vous pouvez créer arbitraire long des pipelines sans recourir à "déléguer une partie du travail à la coquille". Malheureusement, le sous-processus de la documentation ne pas le mentionner.
Il existe des moyens pour obtenir le même effet sans les tuyaux:
Maintenant utiliser
stdin=tf
pourp_awk
. C'est une question de goût que vous préférez.Ci-dessus est toujours pas à 100% équivalent à bash pipelines, car le traitement du signal est différent. Vous pouvez voir si vous ajoutez un autre tuyau élément qui tronque la sortie de
sort
, par exemplehead -n 10
. Avec le code ci-dessus,sort
permettra d'imprimer un "Broken pipe" message d'erreur àstderr
. Vous ne verrez pas ce message lorsque vous exécutez le même pipeline dans le shell. (C'est la seule différence, le résultat enstdout
est le même). La raison semble être que pythonPopen
jeux deSIG_IGN
pourSIGPIPE
, tandis que la coque laisse auSIG_DFL
, etsort
's de traitement de signal est différent dans ces deux cas.Pour moi, le ci-dessous approche est la plus propre et la plus facile à lire
qui peut être appelé de la sorte: