Si je fais ce qui suit:
import subprocess
from cStringIO import StringIO
subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
Je reçois:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__
(p2cread, p2cwrite,
File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles
p2cread = stdin.fileno()
AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'
Apparemment, un objet cStringIO.StringIO ne s'active pas assez près d'un canard de fichier pour convenir à subprocess.Popen. Comment contourner cela?
python
subprocess
stdin
Daryl Spitzer
la source
la source
call(['ls', '-1'], shell=True)
est incorrect. Je recommande plutôt de lire les questions courantes de la description des balises du sous-processus . En particulier, pourquoi subprocess.Popen ne fonctionne pas lorsque args est une séquence? explique pourquoi acall(['ls', '-1'], shell=True)
tort. Je me souviens d'avoir laissé des commentaires sous le blog, mais je ne les vois pas maintenant pour une raison quelconque.subprocess.run
voir stackoverflow.com/questions/48752152/…Réponses:
Popen.communicate()
Documentation:Ainsi, votre exemple pourrait être écrit comme suit:
Sur la version actuelle de Python 3, vous pouvez utiliser
subprocess.run
, pour passer l'entrée sous forme de chaîne à une commande externe et obtenir son état de sortie, et sa sortie sous forme de chaîne en un seul appel:la source
J'ai compris cette solution de contournement:
Y en a t-il un meilleur?
la source
stdin.write()
utilisation est déconseillée,p.communicate()
doit être utilisée. Voir ma réponse.communicate
fermera le canal et permettra au processus de se terminer normalement.read()
partir de cela, commecommunicate()
même sans argument).Je suis un peu surpris que personne n'ait suggéré de créer un pipe, ce qui est à mon avis le moyen le plus simple de passer une chaîne à stdin d'un sous-processus:
la source
os
et lasubprocess
documentation conviennent tous deux que vous devriez préférer ce dernier au premier. Il s'agit d'une solution héritée qui a un remplacement standard (légèrement moins concis); la réponse acceptée cite la documentation pertinente.Il existe une belle solution si vous utilisez Python 3.4 ou mieux. Utilisez l'
input
argument au lieu de l'stdin
argument, qui accepte un argument octets:Cela fonctionne pour
check_output
etrun
, mais pascall
oucheck_call
pour une raison quelconque.la source
check_output
devrait avoir uninput
argument, mais pascall
.check_call
mais cela fonctionne pourrun
. Il fonctionne également avec input = string tant que vous passez également un argument de codage selon la documentation.J'utilise python3 et j'ai découvert que vous devez encoder votre chaîne avant de pouvoir la passer dans stdin:
la source
b'something'
). Il renverra également err et out en octets. Si vous voulez éviter cela, vous pouvez passeruniversal_newlines=True
àPopen
. Ensuite, il acceptera l'entrée comme str et renverra également err / out comme str.universal_newlines=True
convertira également vos nouvelles lignes en fonction de votre systèmeJ'ai bien peur que non. Le canal est un concept de système d'exploitation de bas niveau, il nécessite donc absolument un objet fichier qui est représenté par un descripteur de fichier de niveau système d'exploitation. Votre solution de contournement est la bonne.
la source
la source
Attention, cela
Popen.communicate(input=s)
peut vous poser des problèmes s'ils
est trop volumineux, car apparemment le processus parent le tamponnera avant de bifurquer le sous-processus enfant, ce qui signifie qu'il a besoin de "deux fois plus" de mémoire utilisée à ce stade (au moins selon l'explication "sous le capot") et la documentation liée trouvée ici ). Dans mon cas particulier,s
était un générateur qui a d'abord été entièrement développé et ensuite seulement écrit, destdin
sorte que le processus parent était énorme juste avant la naissance de l'enfant, et aucune mémoire n'était laissée pour le bifurquer:File "/opt/local/stow/python-2.7.2/lib/python2.7/subprocess.py", line 1130, in _execute_child self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory
la source
la source
shell=True
est si couramment utilisé sans raison valable, et c'est une question populaire, permettez-moi de souligner qu'il y a beaucoup de situations où ilPopen(['cmd', 'with', 'args'])
est nettement préférablePopen('cmd with args', shell=True)
et que le shell décompose la commande et les arguments en jetons, mais ne fournit rien d'autre utile, tout en ajoutant une quantité importante de complexité et donc aussi attaquer la surface.la source
Sur Python 3.7+, procédez comme suit:
et vous voudrez probablement ajouter
capture_output=True
pour obtenir la sortie de l'exécution de la commande sous forme de chaîne.Sur les anciennes versions de Python, remplacez
text=True
paruniversal_newlines=True
:la source