Comment appeler une commande externe (comme si je l'avais tapée au shell Unix ou à l'invite de commande Windows) à partir d'un script Python?
Regardez le module de sous - processus dans la bibliothèque standard:
import subprocess
subprocess.run(["ls", "-l"])
L'avantage de subprocess
rapport system
est qu'il est plus souple (vous pouvez obtenir le stdout
, stderr
, le code d'état « réel », une meilleure gestion des erreurs, etc ...).
La documentation officielle recommande le subprocess
module plutôt que l'alternative os.system()
:
Le
subprocess
module offre des fonctionnalités plus puissantes pour générer de nouveaux processus et récupérer leurs résultats; l'utilisation de ce module est préférable à l'utilisation de cette fonction [os.system()
].
La section Remplacement de fonctions plus anciennes par la section Module de sous-processus de la subprocess
documentation peut contenir des recettes utiles.
Pour les versions de Python antérieures à 3.5, utilisez call
:
import subprocess
subprocess.call(["ls", "-l"])
echo $PATH
en utilisantcall(["echo", "$PATH"])
, mais cela faisait juste écho à la chaîne littérale$PATH
au lieu de faire une substitution. Je sais que je pourrais obtenir la variable d'environnement PATH, mais je me demande s'il existe un moyen facile de faire en sorte que la commande se comporte exactement comme si je l'avais exécutée dans bash.shell=True
pour que cela fonctionne.shell=True
, à cet effet Python est fourni avec os.path.expandvars . Dans votre cas , vous pouvez écrire:os.path.expandvars("$PATH")
. @SethMMorton veuillez reconsidérer votre commentaire -> Pourquoi ne pas utiliser shell = Truefor
boucle, comment puis-je le faire sans qu'il bloque mon script python? Je me fiche de la sortie de la commande, je veux juste en exécuter beaucoup.subprocess
quandshell=False
, alors utilisezshlex.split
pour un moyen facile de le faire docs.python.org/2/library/shlex.html#shlex.splitVoici un résumé des façons d'appeler des programmes externes et les avantages et inconvénients de chacun:
os.system("some_command with args")
transmet la commande et les arguments au shell de votre système. C'est bien parce que vous pouvez réellement exécuter plusieurs commandes à la fois de cette manière et configurer des canaux et une redirection d'entrée / sortie. Par exemple:Cependant, bien que cela soit pratique, vous devez gérer manuellement l'échappement des caractères shell tels que les espaces, etc. D'autre part, cela vous permet également d'exécuter des commandes qui sont simplement des commandes shell et non des programmes réellement externes. Consultez la documentation .
stream = os.popen("some_command with args")
fera la même chose que,os.system
sauf qu'il vous donne un objet de type fichier que vous pouvez utiliser pour accéder à l'entrée / sortie standard pour ce processus. Il existe 3 autres variantes de popen qui gèrent toutes les E / S légèrement différemment. Si vous passez tout sous forme de chaîne, votre commande est transmise au shell; si vous les passez sous forme de liste, vous n'avez pas à vous soucier de ne rien échapper. Consultez la documentation .La
Popen
classe dusubprocess
module. Ceci est destiné à remplacer,os.popen
mais présente l'inconvénient d'être légèrement plus compliqué en raison de son caractère complet. Par exemple, vous diriez:au lieu de:
mais il est agréable d'avoir toutes les options dans une classe unifiée au lieu de 4 fonctions popen différentes. Consultez la documentation .
La
call
fonction dusubprocess
module. C'est fondamentalement comme laPopen
classe et prend tous les mêmes arguments, mais il attend simplement que la commande se termine et vous donne le code retour. Par exemple:Consultez la documentation .
Si vous utilisez Python 3.5 ou une version ultérieure, vous pouvez utiliser la nouvelle
subprocess.run
fonction, qui ressemble beaucoup à la précédente, mais encore plus flexible et renvoie unCompletedProcess
objet lorsque la commande a terminé son exécution.Le module os a également toutes les fonctions fork / exec / spawn que vous auriez dans un programme C, mais je ne recommande pas de les utiliser directement.
Le
subprocess
module devrait probablement être ce que vous utilisez.Enfin, sachez que pour toutes les méthodes où vous passez la commande finale à exécuter par le shell sous forme de chaîne et que vous êtes responsable de l'échapper. Il y a de sérieuses implications pour la sécurité si une partie de la chaîne que vous passez ne peut pas être entièrement approuvée. Par exemple, si un utilisateur entre une partie ou une partie de la chaîne. En cas de doute, utilisez uniquement ces méthodes avec des constantes. Pour vous donner un aperçu des implications, considérez ce code:
et imaginez que l'utilisateur entre quelque chose "ma maman ne m'aime pas && rm -rf /" qui pourrait effacer tout le système de fichiers.
la source
open
.subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.runsubprocess.run(..)
, que fait exactement "Cela ne capture pas stdout ou stderr par défaut". impliquer? Etsubprocess.check_output(..)
STDERR?echo
devant de la chaîne passée àPopen
? Ainsi, la commande complète seraecho my mama didnt love me && rm -rf /
.subprocess.run()
leurs frèressubprocess.check_call()
et sœurs plus âgés et al. Pour les cas où ceux-ci ne suffisent pas, voirsubprocess.Popen()
.os.popen()
ne devrait peut-être pas être mentionné du tout, ou même après "pirater votre propre code fork / exec / spawn".Implémentation typique:
Vous êtes libre de faire ce que vous voulez avec les
stdout
données du tube. En fait, vous pouvez simplement omettre ces paramètres (stdout=
etstderr=
) et cela se comportera commeos.system()
.la source
.readlines()
lit toutes les lignes à la fois, c'est-à-dire qu'il bloque jusqu'à ce que le sous-processus se termine (ferme son extrémité du tuyau). Pour lire en temps réel (s'il n'y a pas de problème de mise en mémoire tampon), vous pouvez:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(note: nons
à la fin) ne verra aucune donnée jusqu'à ce que l'enfant remplisse sa mémoire tampon. Si l'enfant ne produit pas beaucoup de données, la sortie ne sera pas en temps réel. Voir la deuxième raison dans Q: Pourquoi ne pas simplement utiliser un tuyau (popen ())? . Certaines solutions de contournement sont fournies dans cette réponse (pexpect, pty, stdbuf)Popen
pour des tâches simples. Cela spécifie également inutilementshell=True
. Essayez l'une dessubprocess.run()
réponses.Quelques conseils pour détacher le processus enfant de l'appelant (démarrage du processus enfant en arrière-plan).
Supposons que vous souhaitiez démarrer une longue tâche à partir d'un script CGI. Autrement dit, le processus enfant doit vivre plus longtemps que le processus d'exécution de script CGI.
L'exemple classique de la documentation du module de sous-processus est:
L'idée ici est que vous ne voulez pas attendre dans la ligne 'call subprocess' jusqu'à ce que le longtask.py soit terminé. Mais il n'est pas clair ce qui se passe après la ligne «un peu plus de code ici» de l'exemple.
Ma plate-forme cible était FreeBSD, mais le développement était sur Windows, donc j'ai d'abord rencontré le problème sur Windows.
Sous Windows (Windows XP), le processus parent ne se terminera pas tant que le fichier longtask.py n'aura pas terminé son travail. Ce n'est pas ce que vous voulez dans un script CGI. Le problème n'est pas spécifique à Python; dans la communauté PHP, les problèmes sont les mêmes.
La solution consiste à passer l'indicateur de création de processus DETACHED_PROCESS à la fonction CreateProcess sous-jacente dans l'API Windows. Si vous avez installé pywin32, vous pouvez importer l'indicateur à partir du module win32process, sinon vous devez le définir vous-même:
/ * UPD 2015.10.27 @eryksun dans un commentaire ci-dessous note que l'indicateur sémantiquement correct est CREATE_NEW_CONSOLE (0x00000010) * /
Sur FreeBSD, nous avons un autre problème: lorsque le processus parent est terminé, il termine également les processus enfants. Et ce n'est pas non plus ce que vous voulez dans un script CGI. Certaines expériences ont montré que le problème semblait être lié au partage de sys.stdout. Et la solution de travail était la suivante:
Je n'ai pas vérifié le code sur d'autres plateformes et je ne connais pas les raisons du comportement sur FreeBSD. Si quelqu'un le sait, veuillez partager vos idées. Googler sur le démarrage de processus d'arrière-plan en Python ne fait pas encore la lumière.
la source
DETACHED_PROCESS
encreationflags
évite en empêchant l'enfant d'hériter ou de la création d' une console. Si vous souhaitez plutôt une nouvelle console, utilisezCREATE_NEW_CONSOLE
(0x00000010).os.devnull
parce que certains programmes de console se terminent avec une erreur sinon. Créez une nouvelle console lorsque vous souhaitez que le processus enfant interagisse avec l'utilisateur simultanément avec le processus parent. Il serait déroutant d'essayer de faire les deux dans une seule fenêtre.Notez que cela est dangereux, car la commande n'est pas nettoyée. Je vous laisse le soin de google pour la documentation pertinente sur les modules 'os' et 'sys'. Il existe un tas de fonctions (exec * et spawn *) qui feront des choses similaires.
la source
subprocess
comme une solution légèrement plus polyvalente et portable. L'exécution de commandes externes est bien sûr intrinsèquement non transférable (vous devez vous assurer que la commande est disponible sur toutes les architectures que vous devez prendre en charge) et passer des entrées utilisateur en tant que commande externe est intrinsèquement dangereux.Je recommanderais d'utiliser le module de sous - processus au lieu de os.system car il échappe au shell pour vous et est donc beaucoup plus sûr.
la source
subprocess
quandshell=False
, alors utilisezshlex.split
pour un moyen facile de le faire docs.python.org/2/library/shlex.html#shlex.split ( c'est la manière recommandée selon les documents docs.python.org/2/library/subprocess.html#popen-constructor )Si vous souhaitez renvoyer les résultats de la commande, vous pouvez utiliser
os.popen
. Cependant, cela est obsolète depuis la version 2.6 en faveur du module de sous - processus , que d'autres réponses ont bien couvert.la source
Il existe de nombreuses bibliothèques différentes qui vous permettent d'appeler des commandes externes avec Python. Pour chaque bibliothèque, j'ai donné une description et montré un exemple d'appel d'une commande externe. La commande que j'ai utilisée comme exemple est
ls -l
(lister tous les fichiers). Si vous souhaitez en savoir plus sur l'une des bibliothèques que j'ai répertoriées et lié la documentation de chacune d'entre elles.J'espère que cela vous aidera à prendre une décision sur la bibliothèque à utiliser :)
Le sous-processus vous permet d'appeler des commandes externes et de les connecter à leurs canaux d'entrée / sortie / erreur (stdin, stdout et stderr). Le sous-processus est le choix par défaut pour exécuter des commandes, mais parfois d'autres modules sont meilleurs.
os est utilisé pour les "fonctionnalités dépendantes du système d'exploitation". Il peut également être utilisé pour appeler des commandes externes avec
os.system
etos.popen
(Remarque: il existe également un sous-processus.popen). os exécutera toujours le shell et est une alternative simple pour les personnes qui n'en ont pas besoin ou ne savent pas comment l'utilisersubprocess.run
.sh est une interface de sous-processus qui vous permet d'appeler des programmes comme s'il s'agissait de fonctions. Ceci est utile si vous souhaitez exécuter une commande plusieurs fois.
plumbum est une bibliothèque de programmes Python "de type script". Vous pouvez appeler des programmes comme des fonctions comme dans
sh
. Plumbum est utile si vous souhaitez exécuter un pipeline sans le shell.pexpect vous permet de générer des applications enfants, de les contrôler et de trouver des modèles dans leur sortie. C'est une meilleure alternative au sous-processus pour les commandes qui attendent un tty sur Unix.
fabric est une bibliothèque Python 2.5 et 2.7. Il vous permet d'exécuter des commandes shell locales et distantes. Fabric est une alternative simple pour exécuter des commandes dans un shell sécurisé (SSH)
envoyé est connu comme "sous-processus pour les humains". Il est utilisé comme un emballage pratique autour du
subprocess
module.commands
contient des fonctions wrapper pouros.popen
, mais il a été supprimé de Python 3 carsubprocess
c'est une meilleure alternative.L'édition était basée sur le commentaire de JF Sebastian.
la source
J'utilise toujours
fabric
pour cela des choses comme:Mais cela semble être un bon outil:
sh
(interface de sous-processus Python) .Regardez un exemple:
la source
Vérifiez également la bibliothèque Python "pexpect".
Il permet un contrôle interactif des programmes / commandes externes, même ssh, ftp, telnet, etc. Vous pouvez simplement taper quelque chose comme:
la source
Avec la bibliothèque standard
Utilisez le module de sous - processus (Python 3):
C'est la voie standard recommandée. Cependant, des tâches plus compliquées (tuyaux, sortie, entrée, etc.) peuvent être fastidieuses à construire et à écrire.
Remarque sur la version Python: Si vous utilisez toujours Python 2, subprocess.call fonctionne de la même manière.
ProTip: shlex.split peut vous aider à analyser la commande pour
run
,call
et d'autressubprocess
fonctions au cas où vous ne voudriez pas (ou si vous ne pouvez pas!) Les fournir sous forme de listes:Avec des dépendances externes
Si cela ne vous dérange pas les dépendances externes, utilisez plumbum :
C'est le meilleur
subprocess
emballage. Il est multiplateforme, c'est-à-dire qu'il fonctionne à la fois sur les systèmes Windows et Unix. Installer parpip install plumbum
.Une autre bibliothèque populaire est sh :
Cependant, la
sh
prise en charge de Windows a été supprimée, donc ce n'est plus aussi génial qu'avant. Installer parpip install sh
.la source
Si vous avez besoin de la sortie de la commande que vous appelez, vous pouvez utiliser subprocess.check_output (Python 2.7+).
Notez également le paramètre shell .
la source
check_output
nécessite une liste plutôt qu'une chaîne. Si vous ne comptez pas sur les espaces entre guillemets pour valider votre appel, la façon la plus simple et la plus lisible de le faire estsubprocess.check_output("ls -l /dev/null".split())
.Voici comment j'exécute mes commandes. Ce code a à peu près tout ce dont vous avez besoin
la source
Mise à jour:
subprocess.run
est l'approche recommandée à partir de Python 3.5 si votre code n'a pas besoin de maintenir la compatibilité avec les versions antérieures de Python. Il est plus cohérent et offre une facilité d'utilisation similaire à celle d'Envoy. (La tuyauterie n'est pas aussi simple cependant. Voir cette question pour savoir comment .)Voici quelques exemples de la documentation .
Exécutez un processus:
Augmenter en cas d'échec:
Sortie de capture:
Réponse originale:
Je recommande d'essayer Envoy . C'est un wrapper pour le sous-processus, qui à son tour vise à remplacer les anciens modules et fonctions. Envoy est un sous-processus pour les humains.
Exemple d'utilisation du README :
Tuyau aussi:
la source
Utilisez un sous-processus .
... ou pour une commande très simple:
la source
os.system
est OK, mais un peu daté. Ce n'est pas non plus très sûr. Essayez plutôtsubprocess
.subprocess
n'appelle pas sh directement et est donc plus sécurisé queos.system
.Obtenez plus d'informations ici .
la source
subprocess
ne supprime pas tous les problèmes de sécurité et présente certains problèmes embêtants.Simple, utilisation
subprocess.run
, qui renvoie unCompletedProcess
objet:Pourquoi?
Depuis Python 3.5, la documentation recommande subprocess.run :
Voici un exemple d'utilisation la plus simple possible - et il fait exactement comme demandé:
run
attend que la commande se termine avec succès, puis retourne unCompletedProcess
objet. Il peut à la place augmenterTimeoutExpired
(si vous lui donnez untimeout=
argument) ouCalledProcessError
(s'il échoue et que vous passezcheck=True
).Comme vous pouvez le déduire de l'exemple ci-dessus, stdout et stderr sont tous deux dirigés par défaut vers vos propres stdout et stderr par défaut.
Nous pouvons inspecter l'objet retourné et voir la commande qui a été donnée et le code retour:
Capture de sortie
Si vous souhaitez capturer la sortie, vous pouvez passer
subprocess.PIPE
à la appropriéestderr
oustdout
:(Je trouve intéressant et légèrement contre-intuitif que les informations de version soient mises sur stderr au lieu de stdout.)
Passer une liste de commandes
On pourrait facilement passer de la fourniture manuelle d'une chaîne de commande (comme le suggère la question) à la fourniture d'une chaîne construite par programme. Ne construisez pas de chaînes par programmation. Il s'agit d'un problème de sécurité potentiel. Il vaut mieux supposer que vous ne faites pas confiance à l'entrée.
Remarque, seul
args
doit être passé positionnellement.Signature complète
Voici la signature réelle dans la source et comme indiqué par
help(run)
:Les
popenargs
etkwargs
sont donnés auPopen
constructeur.input
peut être une chaîne d'octets (ou unicode, si vous spécifiez l'encodage ouuniversal_newlines=True
) qui sera redirigée vers le stdin du sous-processus.La documentation décrit
timeout=
etcheck=True
mieux que je ne pouvais:et cet exemple
check=True
est meilleur que celui que je pourrais trouver:Signature étendue
Voici une signature étendue, comme indiqué dans la documentation:
Notez que cela indique que seule la liste des arguments doit être passée de manière positionnelle. Passez donc les arguments restants comme arguments de mots clés.
Popen
Quand l'utiliser à la
Popen
place? J'aurais du mal à trouver un cas d'utilisation basé uniquement sur les arguments. L'utilisation directe dePopen
, cependant, vous donnerait accès à ses méthodes, y comprispoll
«send_signal», «terminate» et «wait».Voici la
Popen
signature donnée dans la source . Je pense que c'est l'encapsulation la plus précise de l'information (par opposition àhelp(Popen)
):Mais la
Popen
documentation est plus informative :Comprendre la documentation restante sur
Popen
sera laissé comme un exercice pour le lecteur.la source
shell=True
ou (mieux encore) passer la commande sous forme de liste.Il y a aussi Plumbum
la source
Utilisation:
os - Ce module fournit une manière portable d'utiliser les fonctionnalités dépendantes du système d'exploitation.
Pour plus de
os
fonctions, voici la documentation.la source
Cela peut être aussi simple:
la source
os.system
recommande explicitement de l'éviter en faveur desubprocess
.J'aime bien shell_command pour sa simplicité. Il est construit au-dessus du module de sous-processus.
Voici un exemple tiré de la documentation:
la source
Il y a une autre différence ici qui n'est pas mentionnée précédemment.
subprocess.Popen
exécute la <commande> en tant que sous-processus. Dans mon cas, j'ai besoin d'exécuter le fichier <a> qui doit communiquer avec un autre programme, <b>.J'ai essayé le sous-processus et l'exécution a réussi. Cependant, <b> n'a pas pu communiquer avec <a>. Tout est normal lorsque je lance les deux depuis le terminal.
Un de plus: (REMARQUE: kwrite se comporte différemment des autres applications. Si vous essayez ce qui suit avec Firefox, les résultats ne seront pas les mêmes.)
Si vous essayez
os.system("kwrite")
, le flux du programme se bloque jusqu'à ce que l'utilisateur ferme kwrite. Pour surmonter cela, j'ai plutôt essayéos.system(konsole -e kwrite)
. Ce programme horaire a continué de couler, mais kwrite est devenu le sous-processus de la console.N'importe qui exécute le kwrite n'étant pas un sous-processus (c'est-à-dire que dans le moniteur du système, il doit apparaître au bord le plus à gauche de l'arborescence).
la source
os.system
ne vous permet pas de stocker les résultats, donc si vous voulez stocker les résultats dans une liste ou quelque chose, çasubprocess.call
fonctionne.la source
subprocess.check_call
est pratique si vous ne souhaitez pas tester les valeurs de retour. Il lève une exception sur toute erreur.la source
J'ai tendance à utiliser un sous-processus avec shlex (pour gérer l'échappement des chaînes entre guillemets):
la source
Plug sans vergogne, j'ai écrit une bibliothèque pour cela: P https://github.com/houqp/shell.py
C'est essentiellement un emballage pour popen et shlex pour l'instant. Il prend également en charge les commandes de canalisation afin que vous puissiez enchaîner les commandes plus facilement en Python. Vous pouvez donc faire des choses comme:
la source
Sous Windows, vous pouvez simplement importer le
subprocess
module et exécuter des commandes externes en appelantsubprocess.Popen()
,subprocess.Popen().communicate()
etsubprocess.Popen().wait()
comme ci-dessous:Production:
la source
Sous Linux, au cas où vous voudriez appeler une commande externe qui s'exécutera indépendamment (continuera à s'exécuter après la fin du script python), vous pouvez utiliser une simple file d'attente comme spouleur de tâches ou at commande
Un exemple avec le spouleur de tâches:
Remarques sur le spouleur de tâches (
ts
):Vous pouvez définir le nombre de processus simultanés à exécuter ("slots") avec:
ts -S <number-of-slots>
L'installation
ts
ne nécessite pas de privilèges d'administrateur. Vous pouvez le télécharger et le compiler à partir de la source avec un simplemake
, l'ajouter à votre chemin et vous avez terminé.la source
ts
n'est pas standard sur aucune distribution que je connaisse, bien que le pointeur versat
soit légèrement utile. Vous devriez probablement aussi mentionnerbatch
. Comme ailleurs, laos.system()
recommandation devrait probablement mentionner au moins qu'ilsubprocess
s'agit de son remplacement recommandé.Vous pouvez utiliser Popen, puis vous pouvez vérifier l'état de la procédure:
Découvrez subprocess.Popen .
la source
Pour récupérer l'ID réseau à partir du neutron OpenStack :
Sortie de nova net-list
Sortie d' impression (networkId)
la source
os.popen()
en 2016. Le script Awk pourrait facilement être remplacé par du code Python natif.