Assegnare l'output di os.system a una variabile e impedirne la visualizzazione sullo schermo


305

Voglio assegnare l'output di un comando che eseguo utilizzando os.systema una variabile e impedirne l'output sullo schermo. Ma, nel codice seguente, l'output viene inviato allo schermo e il valore stampato per varè 0, che suppongo significhi se il comando è stato eseguito correttamente o meno. Esiste un modo per assegnare l'output del comando alla variabile e impedirne la visualizzazione sullo schermo?

var = os.system("cat /etc/services")
print var #Prints 0

2
possibile duplicato di Equivalent of Backticks in Python
msw,

4
Non usare os.system(né os.popen, per la risposta che hai accettato): usa subprocess.Popen, è molto meglio!
Alex Martelli,

1
@AlexMartelli, non è possibile utilizzare comandi complessi (ad es. Piped) in subprocess.Popen (), ma con os.system si può
vak

2
@vak, ovviamente puoi usare pipe & c w / subprocess.Popen- basta aggiungere shell=True!
Alex Martelli,

@AlexMartelli shell=Trueè (generalmente) una pessima idea! Devi essere molto sicuro di quello che stai eseguendo :)
Ignacio Fernández,

Risposte:


444

Da " Equivalent of Bash Backticks in Python ", che ho chiesto molto tempo fa, ciò che potresti voler usare è popen:

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

Dai documenti per Python 3.6 ,

Questo è implementato usando subprocess.Popen; consultare la documentazione di quella classe per modi più potenti di gestire e comunicare con i sottoprocessi.


Ecco il codice corrispondente per subprocess:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out

6
Si noti che la subprocess.check_outputsoluzione di Walter è più vicina al one-liner Pythonic sembra che tu stia cercando, purché non ti interessi stderr.
Chbrown,

11
@ChrisBunch Perché Suprocess è una soluzione migliore di os.popen?
Martin Thoma,

6
Non dovresti (quasi) mai usare shell=True. Vedi docs.python.org/3/library/…
dylnmc,

44
Continuo a imbattermi in questo e ogni volta che mi chiedo: perché è meglio avere tre righe di codice complicato piuttosto che una riga di codice evidente?
Ant6n,

3
Non solo non dovresti (quasi) mai usarlo shell=True, ma è anche errato in questo caso. shell=Truerende la shell il processo figlio anziché cat, quindi oute errsono lo stdout / stderr del processo shell anziché del catprocesso
villapx,

180

Potresti anche voler guardare il subprocessmodulo, che è stato creato per sostituire l'intera famiglia di popenchiamate di tipo Python .

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

Il vantaggio è che esiste una grande flessibilità nel modo in cui si invocano i comandi, in cui sono collegati i flussi di ingresso / uscita / errore standard, ecc.


2
nota, è check_outputstato aggiunto con Python 2.7 docs.python.org/2.7/library/…
phyatt

1
Aggiungi anche stderr=subprocess.STDOUTper acquisire errori standard
Dolan Antenucci,

47

Il modulo comandi è un modo abbastanza alto livello per farlo:

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

lo stato è 0, l'output è il contenuto di / etc / services.


43
Citando dalla documentazione del modulo comandi : "Obsoleto dalla versione 2.6: Il modulo comandi è stato rimosso in Python 3. Utilizzare invece il modulo sottoprocesso". .
Cristian Ciupitu,

4
sicuramente è obsoleto ma a volte vuoi solo fare qualcosa in modo rapido e semplice in poche righe di codice.
anon58192932

5
@advocate controlla il comando check_output del sottoprocesso. È veloce, facile e non si deprezzerà presto!
Luke Stanley,

29

Per python 3.5+ si consiglia di utilizzare la funzione di esecuzione dal modulo di sottoprocesso . Ciò restituisce un CompletedProcessoggetto, dal quale è possibile ottenere facilmente l'output e il codice di ritorno. Dato che sei interessato solo all'output, puoi scrivere un wrapper di utilità come questo.

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"])

Non dimenticare l'opzione "capture_output = True" per run ()
Elysiumplain l'

24

So che è già stata data una risposta, ma volevo condividere un modo potenzialmente migliore per chiamare Popen tramite l'uso from x import xe le funzioni:

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')

1
3 anni dopo, questo è ciò che ha funzionato per me. L'ho gettato in un file separato chiamato cmd.py, quindi nel mio file principale l'ho scritto from cmd import cmdlinee usato come necessario.
Tariffe KA

1
Stavo riscontrando lo stesso problema con os.system che restituiva 0, ma ho provato questo metodo e funziona benissimo! E come bonus sembra bello e ordinato :) Grazie!
Sophie Muspratt,

4

lo faccio con il file temporaneo 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

1

Python 2.6 e 3 dicono specificamente di evitare l'uso di PIPE per stdout e stderr.

Il modo corretto è

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
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.