Przypisz dane wyjściowe os.system do zmiennej i nie wyświetlaj jej na ekranie

305

Chcę przypisać dane wyjściowe polecenia, którego używam, os.systemdo zmiennej i zapobiec wyświetlaniu jej na ekranie. Ale w poniższym kodzie dane wyjściowe są wysyłane na ekran, a drukowana wartość varto 0, co, jak sądzę, oznacza, czy polecenie zostało wykonane poprawnie, czy nie. Czy istnieje sposób przypisania wyniku polecenia do zmiennej, a także zatrzymania jej wyświetlania na ekranie?

var = os.system("cat /etc/services")
print var #Prints 0
Jan
źródło
2
możliwy duplikat odpowiednika Backticks w Pythonie
msw
4
Nie używaj os.system(ani os.popen, zgodnie z zaakceptowaną odpowiedzią): używaj subprocess.Popen, jest o wiele lepiej!
Alex Martelli,
1
@AlexMartelli, w subprocess.Popen () nie można używać złożonych poleceń (np. Potokowych), ale przy pomocy systemu os.system można
vak
2
@vak, oczywiście możesz używać rur i cw / subprocess.Popen- po prostu dodaj shell=True!
Alex Martelli
@AlexMartelli shell=Trueto (ogólnie) bardzo zły pomysł! Musisz być bardzo pewny tego, co wykonujesz :)
Ignacio Fernández,

Odpowiedzi:

444

Z „ Equivalent of Bash Backticks in Python ”, o które pytałem dawno temu, możesz chcieć użyć popen:

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

Z dokumentacji dla Python 3.6 ,

Jest to realizowane za pomocą subprocess.Popen; zapoznaj się z dokumentacją tej klasy, aby uzyskać bardziej zaawansowane sposoby zarządzania podprocesami i komunikowania się z nimi.


Oto odpowiedni kod dla subprocess:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out
Chris Bunch
źródło
6
Zauważ, że subprocess.check_outputrozwiązanie Waltera jest bliższe jednoniciowej wersji Pythona, wydaje się, że szukasz, o ile się nie przejmujesz stderr.
chbrown,
11
@ChrisBunch Dlaczego suprocess jest lepszym rozwiązaniem niż os.popen?
Martin Thoma
6
Nigdy nie należy (prawie) używać shell=True. Zobacz docs.python.org/3/library/…
dylnmc
44
Ciągle się z tym spotykam i za każdym razem zastanawiam się - dlaczego lepiej mieć trzy linie skomplikowanego kodu zamiast jednej linii oczywistego kodu?
Ant6n
3
Nie tylko powinieneś (prawie) nigdy nie używać shell=True, ale także w tym przypadku jest to nieprawidłowe. shell=Truesprawia, że powłoka proces dziecko zamiast cat, tak outi errsą stdout / stderr z muszli procesu zamiast tego catprocesu
villapx
180

Możesz także zajrzeć do subprocessmodułu, który został zbudowany w celu zastąpienia całej rodziny popenwywołań typu Python .

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

Zaletą jest to, że istnieje mnóstwo elastyczności w sposobie wywoływania poleceń, w których połączone są standardowe strumienie wejścia / wyjścia / błędu itp.

Walter Mundt
źródło
2
Uwaga, check_outputdodano z python 2.7 docs.python.org/2.7/library/...
phyatt
1
Dodaj także stderr=subprocess.STDOUTdo przechwytywania standardowych błędów
Dolan Antenucci
47

Moduł poleceń jest dość wysokim sposobem na zrobienie tego:

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

status to 0, wyjście to zawartość / etc / services.

ianmclaury
źródło
43
Cytując z dokumentacji modułu poleceń : „Przestarzałe od wersji 2.6: Moduł poleceń został usunięty w Pythonie 3. Zamiast tego należy użyć modułu podprocesu”. .
Cristian Ciupitu
4
pewnie to jest przestarzałe, ale czasami chcesz po prostu szybko i łatwo coś zrobić za pomocą kilku linii kodu.
anon58192932
5
@ advocate sprawdź komendę check_output podprocesu. Jest to szybkie, łatwe i nie będzie szybko tracić wartości!
Luke Stanley
29

W przypadku python 3.5+ zaleca się użycie funkcji uruchamiania z modułu podprocesu . Zwraca CompletedProcessobiekt, z którego można łatwo uzyskać wynik, a także kod powrotu. Ponieważ interesuje Cię tylko wyjście, możesz napisać takie opakowanie narzędzia.

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
źródło
Nie zapomnij opcji „capture_output = True” dla run ()
Elysiumplain
24

Wiem, że już na nie odpowiedziano, ale chciałem udostępnić potencjalnie lepiej wyglądający sposób dzwonienia do Popena za pomocą from x import xfunkcji i:

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')
Wasilij Syrakis
źródło
1
3 lata później to działało dla mnie. Wrzuciłem to do osobnego pliku o nazwie cmd.py, a następnie w moim głównym pliku napisałem from cmd import cmdlinei użyłem go w razie potrzeby.
Fares KA
1
Otrzymywałem ten sam problem ze zwracaniem przez system os.system 0, ale wypróbowałem tę metodę i działa ona świetnie! A jako bonus wygląda ładnie i schludnie :) Dzięki!
Sophie Muspratt,
4

robię to z plikiem temp.s.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
źródło
1

Python 2.6 i 3 wyraźnie mówią, aby unikać używania PIPE dla stdout i stderr.

Prawidłowy sposób to

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
źródło