Mon script python (python 3.4.3) appelle un script bash via un sous-processus:
import subprocess as sp
res = sp.check_output("bashscript", Shell=True)
bashscript contient la ligne suivante:
ssh -MNf somehost
qui ouvre une connexion principale partagée à un hôte distant pour permettre certaines opérations ultérieures.
Lors de l'exécution du script python, il demandera le mot de passe pour la ligne ssh
mais il se bloquera après la saisie du mot de passe et ne reviendra jamais. Lorsque je ctrl-C pour terminer le , je vois que la connexion a été correctement établie (donc la ligne ssh
a été exécutée avec succès).
Je n'ai pas ce problème de blocage lors de l'utilisation de check_call
au lieu de check_output
, mais check_call
ne récupère pas stdout. Je voudrais comprendre ce qui cause exactement le comportement de blocage pour check_output
, probablement lié à une certaine subtilité avec ssh -MNf
.
check_call()
retourne dès que le processus /bin/sh
se termine sans attendre les processus descendants.
check_output()
attend jusqu'à ce que toutes les sorties soient lues. Si ssh
hérite du tube, check_output()
attendra sa sortie (jusqu'à ce qu'il ferme ses extrémités de tube héritées).
check_call()
exemple de code:
#!/usr/bin/env python
import subprocess
import sys
import time
start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' &"
subprocess.check_call(cmd, Shell=True)
assert (time.time() - start) < 1
La sortie n'est pas lue; check_call()
retourne immédiatement sans attendre l'arrière-plan du petit-enfant python.
check_call()
est juste Popen().wait()
. Popen()
démarre le processus externe et retourne immédiatement sans attendre sa sortie. .wait()
collecte l'état de sortie du processus - il n'attend pas d'autres processus (petits-enfants).
Si la sortie est lue (elle est redirigée et le petit-enfant python hérite du canal stdout):
start = time.time()
subprocess.check_output(cmd, Shell=True)
assert (time.time() - start) > 2
puis il attend que le processus d'arrière-plan python qui a hérité du canal se termine.
check_output()
appelle Popen().communicate()
, pour obtenir la sortie. .communicate()
appelle .wait()
en interne, c'est-à-dire que check_output()
attend également la fermeture du shell et check_output()
attend EOF.
Si le petit-enfant n'hérite pas du tube, check_output()
ne l'attend pas:
start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' >/dev/null &"
subprocess.check_output(cmd, Shell=True)
assert (time.time() - start) < 1
La sortie de petit-enfant est redirigée vers /dev/null
C'est-à-dire qu'elle n'hérite pas du tube du parent et donc check_output()
peut se terminer sans l'attendre.
Remarque: &
À la fin, ce qui met le petit-enfant python processus en arrière-plan. Cela ne fonctionnera pas sous Windows où Shell=True
Commence cmd.exe
par défaut.