web-dev-qa-db-fra.com

Stocker la sortie de l'appel subprocess.Popen dans une chaîne

J'essaie de passer un appel système dans Python et de stocker la sortie dans une chaîne que je peux manipuler dans le programme Python.

#!/usr/bin/python
import subprocess
p2 = subprocess.Popen("ntpq -p")

J'ai essayé plusieurs choses, y compris certaines des suggestions suivantes:

Récupération de la sortie de subprocess.call ()

mais sans aucune chance.

272
Mark

Dans Python 2.7 ou Python 3

Au lieu de créer directement un objet Popen, vous pouvez utiliser la fonction subprocess.check_output() pour stocker le résultat d'une commande dans une chaîne:

from subprocess import check_output
out = check_output(["ntpq", "-p"])

Dans Python 2.4-2.6

Utilisez la méthode communicate.

import subprocess
p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE)
out, err = p.communicate()

out est ce que vous voulez.

Note importante à propos des autres réponses

Notez comment je suis passé dans la commande. L'exemple "ntpq -p" soulève un autre problème. Puisque Popen n'appelle pas le shell, vous devez utiliser une liste de la commande et des options —["ntpq", "-p"].

433
Mike Graham

Cela a fonctionné pour moi pour rediriger stdout (stderr peut être traité de la même manière):

from subprocess import Popen, PIPE
pipe = Popen(path, stdout=PIPE)
text = pipe.communicate()[0]

Si cela ne fonctionne pas pour vous, veuillez préciser le problème que vous rencontrez.

37
Eli Bendersky

En supposant que pwd ne soit qu'un exemple, voici comment procéder:

import subprocess

p = subprocess.Popen("pwd", stdout=subprocess.PIPE)
result = p.communicate()[0]
print result

Voir le documentation du sous-processus pour n autre exemple et plus d'informations.

22
Mark Byers

subprocess.Popen: http://docs.python.org/2/library/subprocess.html#subprocess.Popen

import subprocess

command = "ntpq -p"  # the Shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, Shell=True)

#Launch the Shell command:
output = process.communicate()

print output[0]

Dans le constructeur Popen, si Shell est True , vous devez passer le commande sous forme de chaîne plutôt que sous forme de séquence. Sinon, divisez simplement la commande en une liste:

command = ["ntpq", "-p"]  # the Shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)

Si vous devez également lire l'erreur standard, dans l'initialisation de Popen, vous pouvez définir stderr sur subprocess.PIPE. ou à sous-processus.STDOUT :

import subprocess

command = "ntpq -p"  # the Shell command
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, Shell=True)

#Launch the Shell command:
output, error = process.communicate()
21
Paolo Rovelli

Cela fonctionne parfaitement pour moi:

import subprocess
try:
    #prints results and merges stdout and std
    result = subprocess.check_output("echo %USERNAME%", stderr=subprocess.STDOUT, Shell=True)
    print result
    #causes error and merges stdout and stderr
    result = subprocess.check_output("copy testfds", stderr=subprocess.STDOUT, Shell=True)
except subprocess.CalledProcessError, ex: # error code <> 0 
    print "--------error------"
    print ex.cmd
    print ex.message
    print ex.returncode
    print ex.output # contains stdout and stderr together 
11
Patrick Wolf

pour Python 2.7+ la réponse idiomatique consiste à utiliser subprocess.check_output()

Vous devriez également noter le traitement des arguments lors de l'appel d'un sous-processus, car cela peut être un peu déroutant ....

Si args est juste une commande unique sans argument (ou si vous avez Shell=True set), il peut s'agir d'une chaîne. Sinon, ce doit être une liste.

par exemple ... pour invoquer la commande ls, tout va bien:

from subprocess import check_call
check_call('ls')

alors est-ce:

from subprocess import check_call
check_call(['ls',])

cependant, si vous voulez passer des arguments à la commande Shell, vous ne pouvez pas faire ceci:

from subprocess import check_call
check_call('ls -al')

au lieu de cela, vous devez le transmettre sous forme de liste:

from subprocess import check_call
check_call(['ls', '-al'])

la fonction shlex.split() peut parfois être utile pour scinder une chaîne en syntaxe similaire à celle d'un shell avant de créer un sous-processus ... comme ceci:

from subprocess import check_call
import shlex
check_call(shlex.split('ls -al'))
11
Corey Goldberg

C'était parfait pour moi. Vous obtiendrez le code de retour, stdout et stderr dans un tuple.

from subprocess import Popen, PIPE

def console(cmd):
    p = Popen(cmd, Shell=True, stdout=PIPE)
    out, err = p.communicate()
    return (p.returncode, out, err)

Par exemple:

result = console('ls -l')
print 'returncode: %s' % result[0]
print 'output: %s' % result[1]
print 'error: %s' % result[2]
8
gravmatt

J'ai écrit une petite fonction basée sur les autres réponses ici:

def pexec(*args):
    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0].rstrip()

Usage:

changeset = pexec('hg','id','--id')
branch = pexec('hg','id','--branch')
revnum = pexec('hg','id','--num')
print('%s : %s (%s)' % (revnum, changeset, branch))
4
mpen
 import os   
 list = os.popen('pwd').read()

Dans ce cas, vous n'aurez qu'un seul élément dans la liste.

4
Alex
import subprocess
output = str(subprocess.Popen("ntpq -p",Shell = True,stdout = subprocess.PIPE, 
stderr = subprocess.STDOUT).communicate()[0])

Ceci est une solution en une seule ligne

1
Kirti Kedia

Ce qui suit capture stdout et stderr du processus dans une seule variable. Il est compatible Python 2 et 3:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

Si votre commande est une chaîne plutôt qu'un tableau, préfixez ceci avec:

import shlex
command = shlex.split(command)
0
Zags