Assignez la sortie de os.system à une variable et empêchez-la d'être affichée à l'écran

305

Je veux affecter la sortie d'une commande que j'exécute os.systemà une variable et l'empêcher d'être sortie à l'écran. Mais, dans le code ci-dessous, la sortie est envoyée à l'écran et la valeur imprimée pour var0, ce qui signifie, je suppose, si la commande s'est exécutée avec succès ou non. Existe-t-il un moyen d'affecter la sortie de la commande à la variable et de l'empêcher de s'afficher à l'écran?

var = os.system("cat /etc/services")
print var #Prints 0
John
la source
2
doublon possible de l' équivalent des backticks en Python
msw
4
N'utilisez pas os.system(ni os.popen, selon la réponse que vous avez acceptée): utilisez subprocess.Popen, c'est bien mieux!
Alex Martelli
1
@AlexMartelli, on ne peut pas utiliser de commandes complexes (par exemple piped) dans subprocess.Popen (), mais avec os.system on peut
vak
2
@vak, bien sûr, vous pouvez utiliser des tuyaux et c w subprocess.Popen- - ajoutez simplement shell=True!
Alex Martelli
@AlexMartelli shell=Trueest (généralement) une très mauvaise idée! Vous devez être très sûr de ce que vous exécutez :)
Ignacio Fernández

Réponses:

444

De " Equivalent of Bash Backticks in Python ", que j'ai demandé il y a longtemps, ce que vous voudrez peut-être utiliser est popen:

os.popen('cat /etc/services').read()

À partir des documents pour Python 3.6 ,

Ceci est implémenté en utilisant subprocess.Popen; consultez la documentation de cette classe pour des moyens plus puissants de gérer et de communiquer avec les sous-processus.


Voici le code correspondant pour subprocess:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out
Chris Bunch
la source
6
Notez que la subprocess.check_outputsolution de Walter est plus proche de la doublure Pythonic qu'il semble que vous recherchez, tant que vous ne vous en souciez pas stderr.
chbrown
11
@ChrisBunch Pourquoi le suprocess est-il une meilleure solution que os.popen?
Martin Thoma
6
Vous ne devriez (presque) jamais utiliser shell=True. Voir docs.python.org/3/library/…
dylnmc
44
Je continue de rencontrer cela et chaque fois que je me demande - pourquoi est-il préférable d'avoir trois lignes de code compliqué plutôt qu'une ligne de code évident?
Ant6n
3
Non seulement vous ne devez (presque) jamais l'utiliser shell=True, mais c'est également incorrect dans ce cas. shell=Truefait du shell le processus enfant plutôt que cat, donc outet errsont les stdout / stderr du processus shell plutôt que du catprocessus
villapx
180

Vous pourriez également vouloir regarder le subprocessmodule, qui a été construit pour remplacer toute la famille de Pythonpopen appels de type .

import subprocess
output = subprocess.check_output("cat /etc/services", shell=True)

L'avantage qu'il a est qu'il y a une tonne de flexibilité avec la façon dont vous appelez les commandes, où les flux d'entrée / sortie / erreur standard sont connectés, etc.

Walter Mundt
la source
2
note, a check_outputété ajouté avec python 2.7 docs.python.org/2.7/library/…
phyatt
1
Ajouter stderr=subprocess.STDOUTpour capturer également les erreurs standard
Dolan Antenucci
47

Le module de commandes est un moyen raisonnablement de haut niveau de le faire:

import commands
status, output = commands.getstatusoutput("cat /etc/services")

l'état est 0, la sortie est le contenu de / etc / services.

ianmclaury
la source
43
Citant la documentation du module de commandes : "Déconseillé depuis la version 2.6: le module de commandes a été supprimé en Python 3. Utilisez plutôt le module de sous-processus." .
Cristian Ciupitu
4
bien sûr, il est obsolète, mais parfois vous voulez juste faire quelque chose rapidement et facilement en quelques lignes de code.
anon58192932
5
@advocate extrait la commande check_output du sous-processus. C'est rapide, facile et ne se dépréciera pas de sitôt!
Luke Stanley
29

Pour python 3.5+, il est recommandé d'utiliser la fonction d'exécution du module de sous-processus . Cela renvoie un CompletedProcessobjet, à partir duquel vous pouvez facilement obtenir la sortie ainsi que le code retour. Comme vous n'êtes intéressé que par la sortie, vous pouvez écrire un wrapper utilitaire comme celui-ci.

from subprocess import PIPE, run

def out(command):
    result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
    return result.stdout

my_output = out("echo hello world")
# Or
my_output = out(["echo", "hello world"])
Chiel ten Brinke
la source
N'oubliez pas l'option "capture_output = True" pour run ()
Elysiumplain
24

Je sais que cela a déjà été répondu, mais je voulais partager un moyen potentiellement meilleur d'appeler Popen via l'utilisation de from x import xet les fonctions:

from subprocess import PIPE, Popen


def cmdline(command):
    process = Popen(
        args=command,
        stdout=PIPE,
        shell=True
    )
    return process.communicate()[0]

print cmdline("cat /etc/services")
print cmdline('ls')
print cmdline('rpm -qa | grep "php"')
print cmdline('nslookup google.com')
Vasili Syrakis
la source
1
3 ans plus tard, c'est ce qui a fonctionné pour moi. J'ai jeté cela dans un fichier distinct appelé cmd.py, puis dans mon fichier principal, j'ai écrit from cmd import cmdlineet utilisé au besoin.
Fares KA
1
J'obtenais le même problème avec os.system renvoyant 0, mais j'ai essayé cette méthode et cela fonctionne très bien! Et en prime, il a l'air bien et bien rangé :) Merci!
Sophie Muspratt
4

je le fais avec le fichier temp os.system:

import tempfile,os
def readcmd(cmd):
    ftmp = tempfile.NamedTemporaryFile(suffix='.out', prefix='tmp', delete=False)
    fpath = ftmp.name
    if os.name=="nt":
        fpath = fpath.replace("/","\\") # forwin
    ftmp.close()
    os.system(cmd + " > " + fpath)
    data = ""
    with open(fpath, 'r') as file:
        data = file.read()
        file.close()
    os.remove(fpath)
    return data
lexa-b
la source
1

Python 2.6 et 3 disent spécifiquement d'éviter d'utiliser PIPE pour stdout et stderr.

La bonne façon est

import subprocess

# must create a file object to store the output. Here we are getting
# the ssid we are connected to
outfile = open('/tmp/ssid', 'w');
status = subprocess.Popen(["iwgetid"], bufsize=0, stdout=outfile)
outfile.close()

# now operate on the file
Kearney Taaffe
la source