2009-09-03 8 views
2

Je jouais avec le module de sous-processus de Python, en essayant quelques exemples mais je n'arrive pas à faire fonctionner les instructions heredoc.Sous-processus Python avec heredocs

Voici l'exemple trivial, je jouais avec:

import subprocess 
a = "A String of Text" 
p = subprocess.Popen(["cat", "<<DATA\n" + a + "\nDATA"]) 

Je reçois l'erreur suivante lorsque je lance le code ci-dessus:

cat: <<DATA\nA String of Text\nDATA: No such file or directory 

Est-ce que je fais mal? Est-ce seulement possible? Si oui, comment ferais-je?


Mise à jour

Je voulais juste dire que cela ne devrait jamais être réalisée en un véritable programme de python, car il y a de meilleures façons de le faire.

Répondre

4

Le support "hérédoc" du shell est une fonction shell. subprocess.Popen n'exécute pas votre commande via le shell par défaut, donc cette syntaxe ne fonctionnera certainement pas.

Cependant, comme vous utilisez des tuyaux, il n'est pas nécessaire d'utiliser le support heredoc du shell. Il suffit d'écrire votre chaîne a dans le tube stdin du processus que vous venez de démarrer. C'est exactement ce que l'obus ferait avec l'hérédoc de toute façon.

Vous pouvez le faire avec Popen.communicate():

p.communicate(a) 

La valeur de retour de la fonction communicate() contient la sortie du processus (en deux courants, voir les docs).

+0

Je n'ai pas tout à fait compris ce que le paramètre Shell a fait. Les docs expliquent très bien ce qui se passe quand vous le définissez sur true mais pas tellement quand il est défini sur false. – MitMaro

+1

Lorsque le paramètre 'shell' est' False', le module 'subprocess' exécute directement le programme que vous spécifiez (dans votre cas, probablement'/bin/cat') avec exactement les arguments spécifiés dans l'appel 'Popen()' .Aucune interprétation de caractères shell tels que redirection ou tuyaux ou quoi que ce soit n'est fait, le programme voit exactement ce que vous lui envoyez. C'est pourquoi 'cat' dit qu'il n'a pas pu trouver le fichier dont le nom a commencé avec' << DATA'. –

+0

Merci pour l'explication, clarifié plusieurs choses. – MitMaro

2

Vous transmettez la syntaxe du shell en tant qu'arguments au programme cat. Vous pouvez essayer de le faire comme ça:

p = subprocess.Popen(["sh", "-c", "cat <<DATA\n" + a + "\nDATA"]) 

Mais le concept lui-même est faux. Vous devriez utiliser les fonctionnalités de Python au lieu d'appeler des scripts shell dans vos scripts python.

Et dans ce cas particulier, vous devriez utiliser la syntaxe heredoc de ce shell pour interpoler les variables, donc vous devrez échapper tout le texte à l'intérieur a et vous assurer qu'il n'y a pas de ligne DATA dedans.


Pour équivalent Python, je pense que le plus proche idée de ce (en supposant que vous ne voulez pas seulement print(a) ;-)) passe la valeur de la variable à stdin d'un processus donné naissance:

p = subprocess.Popen(["program", ...], stdin=subprocess.PIPE) 
p.communicate(a) 
+0

Ceci est une réponse utile. Ce serait encore mieux si vous pouviez donner des suggestions de code pour savoir comment faire cela de façon Pythonienne. –

+0

Comme je l'ai dit dans ma question, c'était juste de jouer avec un sous-processus et je ne ferais jamais quelque chose comme appeler 'cat' en Python. C'était plus par curiosité que pour une utilisation en code réel. – MitMaro

+0

"Vous devriez utiliser des fonctionnalités Python au lieu d'appeler des scripts shell dans vos scripts python." Toutes les fonctionnalités du shell ne sont pas disponibles en Python. Un heredoc peut être utilisé pour de nombreux types de programmes qui n'ont pas d'interface Python, et le contenu de l'heredoc peut être généré dynamiquement avec Python. – user5359531

3

Comme d'autres l'ont souligné, vous devez l'exécuter dans un shell. Popen rend cela facile avec un shell = True argument. Je reçois la sortie suivante:

>>> import subprocess 
>>> a = "A String of Text" 
>>> p = subprocess.Popen("cat <<DATA\n" + a + "\nDATA", shell=True) 
>>> A String of Text 

>>> p.wait() 
0