Memorizza l'output del sottoprocesso. Apri la chiamata in una stringa


300

Sto provando a effettuare una chiamata di sistema in Python e memorizzare l'output in una stringa che posso manipolare nel programma Python.

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

Ho provato alcune cose tra cui alcuni dei suggerimenti qui:

Recupero dell'output di subprocess.call ()

ma senza fortuna.


3
È sempre consigliabile pubblicare il codice effettivo eseguito e il traceback effettivo o il comportamento imprevisto per domande concrete come questa. Ad esempio, non so che cosa hai provato a fare per ottenere l'output e sospetto che in realtà non sei arrivato così lontano per iniziare — avresti avuto un errore nel non trovare il file "ntpq -p", che è una parte diversa di il problema di quello che stai chiedendo.
Mike Graham,

Risposte:


467

In Python 2.7 o Python 3

Invece di creare Popendirettamente un oggetto, è possibile utilizzare la subprocess.check_output()funzione per memorizzare l'output di un comando in una stringa:

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

In Python 2.4-2.6

Usa il communicatemetodo

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

out è quello che vuoi.

Nota importante sulle altre risposte

Nota come ho passato il comando. L' "ntpq -p"esempio solleva un'altra questione. Dato Popenche non invoca la shell, useresti un elenco di comandi e opzioni— ["ntpq", "-p"].


3
In questo caso, Python attende che questa chiamata di sistema finisca? O è necessario chiamare esplicitamente la funzione wait / waitpid?
Nessuna Digitare il

7
@NoneType, Popen.communicatenon restituisce fino al termine del processo.
Mike Graham,

10
se vuoi ottenere un flusso di errori aggiungi stderr:p = subprocess.Popen(["ntpq", "-p"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Timofey,

82
Attento, subprocess.check_output()restituisce un bytesoggetto, non a str. Se tutto ciò che vuoi fare è stampare il risultato, ciò non farà alcuna differenza. Ma se vuoi usare un metodo come myString.split("\n")sul risultato, dovrai prima decodificare l' bytesoggetto: subprocess.check_output(myParams).decode("utf-8")per esempio.
TanguyP,

17
l'aggiunta universal_newlines=Truecome parametro mi ha aiutato in Python 3 a ottenere l'oggetto stringa. Se universal_newlines è True, vengono aperti in modalità testo con codifica predefinita. Altrimenti, vengono aperti come flussi binari.
Jonathan Komar,

38

Questo ha funzionato per me per il reindirizzamento di stdout (stderr può essere gestito in modo simile):

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

Se non funziona per te, specifica esattamente il problema che stai riscontrando.


3
Questo produce qualche oggetto strano. Quando lo converto in stringa, sfugge agli spazi bianchi come \n.
Tomáš Zato - Ripristina Monica il

1
Si noti che ciò non controlla se il sottoprocesso è stato eseguito correttamente. Probabilmente vuoi verificarlo anche pipe.returncode == 0dopo l'ultima riga.
Thakis,

il motivo per cui funziona è perché Popenrestituisce una tupla di stdoute stderr, quindi quando accedi [0]accetti solo il stdout. Potresti anche fare text, err = pipe.communicate()e poi textavrai quello che ti aspetti
Jona,


22

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]

Nel costruttore Popen, se shell è True , dovresti passare il comando come stringa anziché come sequenza. Altrimenti, basta dividere il comando in un elenco:

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

Se è necessario leggere anche l'errore standard, nell'inizializzazione Popen, è possibile impostare stderr su subprocess.PIPE o su subprocess.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()

fantastico questo è quello che stavo cercando
kRazzy R

14

per Python 2.7+ la risposta idiomatica è usare subprocess.check_output()

Si dovrebbe anche notare la gestione degli argomenti quando si richiama un sottoprocesso, in quanto può essere un po 'confuso ....

Se args è solo un singolo comando senza argomenti propri (o hai shell=Trueimpostato), può essere una stringa. Altrimenti deve essere un elenco.

per esempio ... per invocare il lscomando, va bene:

from subprocess import check_call
check_call('ls')

così è questo:

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

tuttavia, se si desidera passare alcuni argomenti al comando shell, non è possibile farlo:

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

invece, devi passarlo come un elenco:

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

la shlex.split()funzione a volte può essere utile per dividere una stringa in una sintassi simile alla shell prima di creare un sottoprocesso ... in questo modo:

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

Cinque anni dopo, questa domanda sta ancora ricevendo molto amore. Grazie per l'aggiornamento 2.7+, Corey!
Marco

11

Questo funziona perfettamente per me:

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 

9

Questo è stato perfetto per me. Otterrai il codice di ritorno, stdout e stderr in una tupla.

from subprocess import Popen, PIPE

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

Per esempio:

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

6

La risposta accettata è ancora buona, solo alcune osservazioni sulle nuove funzionalità. Da Python 3.6, puoi gestire la codifica direttamente in check_output, vedi documentazione . Questo restituisce ora un oggetto stringa:

import subprocess 
out = subprocess.check_output(["ls", "-l"], encoding="utf-8")

In python 3.7, è capture_outputstato aggiunto un parametro a subprocess.run (), che fa parte della gestione Popen / PIPE per noi, vedere i documenti di Python :

import subprocess 
p2 = subprocess.run(["ls", "-l"], capture_output=True, encoding="utf-8")
p2.stdout

4
 import os   
 list = os.popen('pwd').read()

In questo caso, avrai un solo elemento nell'elenco.


7
os.popenè deprecato a favore del subprocessmodulo.
Mike Graham,

3
Questo è stato molto utile per l'amministratore su una vecchia scatola usando la serie 2.2.X di Python.
Neil McF,

4

Ho scritto una piccola funzione basata sulle altre risposte qui:

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

Uso:

changeset = pexec('hg','id','--id')
branch = pexec('hg','id','--branch')
revnum = pexec('hg','id','--num')
print('%s : %s (%s)' % (revnum, changeset, branch))

4

In Python 3.7 è capture_outputstato introdotto un nuovo argomento per parole chiave subprocess.run. Abilitare il breve e semplice:

import subprocess

p = subprocess.run("echo 'hello world!'", capture_output=True, shell=True, encoding="utf8")
assert p.stdout == 'hello world!\n'

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

Questa è una soluzione a una riga


0

Quanto segue cattura stdout e stderr del processo in una singola variabile. È compatibile con Python 2 e 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

Se il tuo comando è una stringa anziché un array, aggiungi questo prefisso con:

import shlex
command = shlex.split(command)

0

Per Python 3.5 ho messo la funzione in base alla risposta precedente. Il registro potrebbe essere rimosso, ma è bello averlo

import shlex
from subprocess import check_output, CalledProcessError, STDOUT


def cmdline(command):
    log("cmdline:{}".format(command))
    cmdArr = shlex.split(command)
    try:
        output = check_output(cmdArr,  stderr=STDOUT).decode()
        log("Success:{}".format(output))
    except (CalledProcessError) as e:
        output = e.output.decode()
        log("Fail:{}".format(output))
    except (Exception) as e:
        output = str(e);
        log("Fail:{}".format(e))
    return str(output)


def log(msg):
    msg = str(msg)
    d_date = datetime.datetime.now()
    now = str(d_date.strftime("%Y-%m-%d %H:%M:%S"))
    print(now + " " + msg)
    if ("LOG_FILE" in globals()):
        with open(LOG_FILE, "a") as myfile:
            myfile.write(now + " " + msg + "\n")

0

Utilizzare il ckeck_outputmetodo disubprocess

import subprocess
address = 192.168.x.x
res = subprocess.check_output(['ping', address, '-c', '3'])

Infine analizza la stringa

for line in res.splitlines():

Spero che sia d'aiuto, buona programmazione

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.