Atribua a saída do os.system a uma variável e impeça que ela seja exibida na tela

305

Quero atribuir a saída de um comando que eu corro usando os.systema uma variável e impedir que ela seja exibida na tela. Mas, no código abaixo, a saída é enviada para a tela e o valor impresso varé 0, o que eu acho que significa se o comando foi executado com êxito ou não. Existe alguma maneira de atribuir a saída do comando à variável e também impedir que ela seja exibida na tela?

var = os.system("cat /etc/services")
print var #Prints 0
John
fonte
2
possível duplicata de Equivalente de Backticks em Python
msw
4
Não use os.system(nem os.popen, de acordo com a resposta que você aceitou): use subprocess.Popen, é muito melhor!
28710 Alex Martelli
1
@AlexMartelli, não se pode usar um comandos complexos (por exemplo, canalizado) em subprocess.popen (), mas com uma os.system pode
VAK
2
@vak, é claro que você pode usar pipes & c w / subprocess.Popen- basta adicionar shell=True!
Alex Martelli
@AlexMartelli shell=Trueé (geralmente) uma péssima idéia! Você tem que estar muito certo de que você está executando :)
Ignacio Fernández

Respostas:

444

Do " Equivalente ao Bash Backticks no Python ", que perguntei há muito tempo, o que você pode querer usar é popen:

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

Nos documentos do Python 3.6 ,

Isso é implementado usando subprocess.Popen; consulte a documentação dessa classe para obter maneiras mais poderosas de gerenciar e se comunicar com subprocessos.


Aqui está o código correspondente para subprocess:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out
Chris Bunch
fonte
6
Observe que a subprocess.check_outputsolução de Walter está mais próxima da linha Pythonic que parece que você está procurando, desde que não se importe stderr.
chbrown
11
@ChrisBunch Por que o suprocessamento é uma solução melhor que os.popen?
Martin Thoma 29/03
6
Você (quase) nunca deve usar shell=True. Veja docs.python.org/3/library/…
dylnmc
44
Eu continuo descobrindo isso e toda vez que me pergunto - por que é melhor ter três linhas de código complicado em vez de uma linha de código óbvio?
Ant6n 27/07/16
3
Você não apenas deve (quase) nunca usar shell=True, como também está incorreto neste caso. shell=Truefaz a desembolsar o processo filho, em vez de cat, por isso, oute errsão o stdout / stderr do shell processo e não do catprocesso
villapx
180

Você também pode querer olhar para o subprocessmódulo, que foi criado para substituir toda a família de popenchamadas do tipo Python .

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

A vantagem é que há muita flexibilidade na maneira como você chama os comandos, onde os fluxos de entrada / saída / erro padrão estão conectados etc.

Walter Mundt
fonte
2
observação, check_outputfoi adicionado com o python 2.7 docs.python.org/2.7/library/…
phyatt
1
Adicionar stderr=subprocess.STDOUTpara capturar erros padrão bem
Dolan Antenucci
47

O módulo de comandos é uma maneira razoavelmente de alto nível para fazer isso:

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

status é 0, saída é o conteúdo de / etc / services.

ianmclaury
fonte
43
Citando a documentação do módulo de comandos : "Descontinuado desde a versão 2.6: O módulo de comandos foi removido no Python 3. Use o módulo de subprocesso." .
Cristian Ciupitu
4
Certifique-se de que está desatualizado, mas às vezes você quer fazer algo de maneira rápida e fácil em algumas linhas de código.
anon58192932
5
@advocate, confira o comando check_output do subprocesso. É rápido, fácil e não depreciará em breve!
Luke Stanley
29

Para python 3.5+, é recomendável usar a função run do módulo de subprocesso . Isso retorna um CompletedProcessobjeto, do qual você pode obter facilmente a saída e o código de retorno. Como você está interessado apenas na saída, é possível escrever um wrapper de utilitário como este.

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
fonte
Não esqueça a opção "capture_output = True" para run ()
Elysiumplain
24

Sei que isso já foi respondido, mas eu queria compartilhar uma maneira potencialmente mais atraente de ligar para o Popen através do uso de from x import xe funções:

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
fonte
1
3 anos depois, foi isso que funcionou para mim. Joguei isso em um arquivo separado chamado cmd.pye, em seguida, no meu arquivo principal, escrevi from cmd import cmdlinee o usei conforme necessário.
Tarifas KA
1
Eu estava recebendo o mesmo problema com o os.system retornando 0, mas tentei esse método e ele funciona muito bem! E como um bônus, parece bonito e arrumado :) Obrigado!
Sophie Muspratt
4

eu faço isso com o arquivo temporário 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
fonte
1

Python 2.6 e 3 dizem especificamente para evitar o uso do PIPE para stdout e stderr.

A maneira correta é

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
fonte