web-dev-qa-db-fra.com

Python: Comment obtenir stdout après avoir lancé os.system?

Je veux obtenir le stdout dans une variable après avoir exécuté l'appel os.system.

Prenons cette ligne comme exemple:

batcmd="dir"
result = os.system(batcmd)

result contiendra le code d'erreur (stderr0 sous Windows ou 1 sous un linux pour l'exemple ci-dessus).

Comment puis-je obtenir le stdout pour la commande ci-dessus sans utiliser la redirection dans la commande exécutée?

74
Eduard Florinescu

Si tout ce dont vous avez besoin est la sortie stdout, jetez un coup d'œil à subprocess.check_output() (ajouté dans Python 2.7):

import subprocess

batcmd="dir"
result = subprocess.check_output(batcmd, Shell=True)

Comme vous utilisiez os.system(), vous devez définir Shell=True pour obtenir le même comportement. Vous voulez tenir compte du gros message d’avertissement rouge concernant le passage d’arguments non fiables à votre shell.

Si vous devez également capturer stderr, ajoutez simplement stderr=subprocess.STDOUT à l'appel:

result = subprocess.check_output([batcmd], stderr=subprocess.STDOUT)

pour rediriger la sortie d'erreur vers le flux de sortie par défaut.

98
Martijn Pieters

Ces réponses n'ont pas fonctionné pour moi. Je devais utiliser ce qui suit:

import subprocess
p = subprocess.Popen(["pwd"], stdout=subprocess.PIPE)
out = p.stdout.read()
print out

Ou en tant que fonction (utiliser Shell = True était requis pour moi le Python 2.6.7 et check_output n'a été ajouté que le 2.7, ce qui le rend inutilisable ici):

def system_call(command):
    p = subprocess.Popen([command], stdout=subprocess.PIPE, Shell=True)
    return p.stdout.read()
20
Patrick

Je voudrais développer la solution Windows. Utiliser IDLE avec Python 2.7.5, quand j'exécute ce code à partir du fichier Expts.py:

import subprocess
r = subprocess.check_output('cmd.exe dir',Shell=False) 
print r

... dans le shell Python, j'obtiens UNIQUEMENT la sortie correspondant à "cmd.exe"; la partie "dir" est ignorée. CEPENDANT, lorsque j'ajoute un commutateur tel que/K ou/C ...

import subprocess
r = subprocess.check_output('cmd.exe /K dir',Shell=False) 
print r

... puis dans le shell Python, j'ai tout ce que j'attendais, y compris la liste des répertoires. Woohoo!

Maintenant, si j’essaie d’utiliser l’une de ces choses sous DOS Python, fenêtre de commande, sans le commutateur ou avec le commutateur/K, il semble que la fenêtre se bloque car elle exécute un sous-processus cmd.exe et il attend d'autres entrées - tapez 'exit' puis appuyez sur [entrée] pour relâcher. Mais avec le commutateur/K, cela fonctionne parfaitement et vous renvoie à l'invite python. Allrightee alors.

Nous sommes allés un peu plus loin ... Je pensais que c'était cool ... Quand je le fais plutôt dans Expts.py:

import subprocess
r = subprocess.call("cmd.exe dir",Shell=False) 
print r

... une nouvelle fenêtre DOS s'ouvre et reste affichée, affichant uniquement les résultats de "cmd.exe" et non de "dir". Lorsque j'ajoute le commutateur/C, la fenêtre DOS s'ouvre et se ferme très rapidement avant que je puisse voir quoi que ce soit (comme prévu, car/C se termine lorsque vous avez terminé). Lorsque j'ajoute le commutateur/K à la place, la fenêtre DOS s'ouvre et reste ouverte, ET j'obtiens tous les résultats attendus, y compris la liste des répertoires.

Si j'essaie la même chose (sous-processus.call au lieu de sous-processus.check_output) à partir d'une fenêtre de commande DOS Python; toutes les sorties sont dans la même fenêtre, il n'y a pas de fenêtres popup. Sans le commutateur, la partie "dir" est à nouveau ignorée ET l'invite passe de l'invite python à l'invite DOS (puisqu'un sous-processus cmd.exe est exécuté en python; tapez à nouveau "exit" et vous-même. reviendra à l'invite python). L'ajout du commutateur/K imprime la liste des répertoires et modifie l'invite de python en DOS car/K ne met pas fin au sous-processus. Le fait de basculer le commutateur sur/C nous donne toutes les sorties attendues ET retourne à l'invite python puisque le sous-processus se termine conformément à/C.

Désolé pour la réponse interminable, mais je suis frustré sur ce forum par les nombreuses "réponses" laconiques qui au mieux ne fonctionnent pas (semble parce qu'elles ne sont pas testées - comme la réponse d'Eduard F au-dessus de la mienne qui manque l'interrupteur) ou Pire, ils sont tellement laconiques qu’ils n’aident pas grand-chose du tout (par exemple, "essayez un sous-processus au lieu de os.system"… ouais, OK, maintenant quoi ??). En revanche, j'ai fourni des solutions que j'ai testées et montré à quel point il existe des différences subtiles entre elles. Cela a pris beaucoup de temps mais ... J'espère que ça aide.

5
LateNiteOwl

commands fonctionne également.

import commands
batcmd = "dir"
result = commands.getoutput(batcmd)
print result

Cela fonctionne sur linux, python 2.7.

3
buxizhizhoum

Je devais utiliser os.system, car le sous-processus me renvoyait une erreur de mémoire pour les tâches plus importantes. Référence pour ce problème ici . Donc, pour obtenir le résultat de la commande os.system, j'ai utilisé cette solution de contournement:

import os

batcmd = 'dir'
result_code = os.system(batcmd + ' > output.txt')
if os.path.exists('output.txt'):
    fp = open('output.txt', "r")
    output = fp.read()
    fp.close()
    os.remove('output.txt')
    print(output)
2
Edhowler