Jak nazywasz polecenie zewnętrzne (jak gdybym wpisał go w wierszu polecenia UNIX lub Windows Command) od skryptu Pythona?

5151
freshWoWer 18 wrzesień 2008, 05:35

27 odpowiedzi

Najlepsza odpowiedź

Spójrz na Moduł podjednostkowy w standardowej bibliotece:

import subprocess
subprocess.run(["ls", "-l"])

Zaletą subprocess vs. system jest to, że jest bardziej elastyczny (możesz uzyskać stdout, stderr, "prawdziwy" kod stanu, lepszego obsługi błędów itp ...).

oficjalna dokumentacja zaleca moduł {X0}} na alternatywnej { {X1}}:

Moduł {X0}} zapewnia silniejsze udogodnienia do tarła nowych procesów i pobieranie ich wyników; Korzystanie z tego modułu jest korzystne dla korzystania z tej funkcji [os.system() ].

Wymiana starszych funkcji z modułem podprocesowym Sekcja w dokumentacji subprocess może mieć pewne pomocne przepisy.

W przypadku wersji Pythona przed 3,5, użyj call:

import subprocess
subprocess.call(["ls", "-l"])
4953
Szymon Bednorz 15 listopad 2020, 03:27

Bez wyjścia wyniku:

import os
os.system("your command here")

Z wynikem wyniku:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
42
Peter Mortensen 28 maj 2017, 22:59

Użyj Moduł OS:

import os
os.system("your command")

Na przykład,

import os
os.system("ifconfig")
25
Peter Mortensen 29 listopad 2019, 22:09

Niektóre wskazówki dotyczące odłączenia procesu dziecka z powołania jednego (rozpoczęcie procesu dziecka w tle).

Załóżmy, że chcesz rozpocząć długą zadanie z skryptu CGI. Oznacza to, że proces dziecka powinien żyć dłużej niż proces wykonania skryptu CGI.

Klasyczny przykład z dokumentacji modułu podprocesowej jest:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

Idea tutaj jest to, że nie chcesz czekać w linii "Call Subprocesess" aż do LongTask.py jest zakończona. Ale nie jest jasne, co dzieje się po linii "trochę więcej kodu tutaj" z przykładu.

Moja platforma docelowa była FreeBSD, ale rozwój był w oknach, więc najpierw skierowałem problem w systemie Windows.

W systemie Windows (Windows XP) proces macierzysty nie zakończy się, dopóki LongTask.py zakończyła swoją pracę. To nie jest to, czego chcesz w skrypcie CGI. Problem nie jest specyficzny dla Pythona; W społeczności PHP problemy są takie same.

Rozwiązaniem jest przejście odłączone_process tworzenie procesów Flaga do podstawowej funkcji createProcess w programie API Windows. Jeśli zdarzy ci się zainstalować Pywin32, możesz zaimportować flagę z modułu Win32Process, w przeciwnym razie powinieneś go zdefiniować:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * Updatek 2015.10.27 @eryksun W komentarzu poniżej Uwagi, że semantycznie poprawna flaga jest create_new_console (0x00000010) * /

Na FreeBSD mamy inny problem: Po zakończeniu procesu macierzystego kończy również procesy dziecięce. I to nie jest to, czego chcesz w skrypcie CGI. Niektóre eksperymenty pokazały, że problem wydawał się być w dzieleniu sys.stdout. A rozwiązanie robocze było następujące:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Nie sprawdziłem kodu na innych platformach i nie znam przyczyn zachowania na FreeBSD. Jeśli ktoś wie, podziel się swoimi pomysłami. Googling na procesach startowych w Pythonie nie rzuca się jeszcze żadnego światła.

242
Peter Mortensen 29 listopad 2019, 21:46
import os
os.system("your command")

Zauważ, że jest to niebezpieczne, ponieważ polecenie nie jest czyszczone. Zostawię to do Google dla odpowiedniej dokumentacji na modułach "OS" i "SYS". Istnieje kilka funkcji (Exec * i Spawn *), które zrobią podobne rzeczy.

165
Peter Mortensen 3 czerwiec 2018, 17:10

Polecam użycie Moduł zamiast OS.System, ponieważ skorupa ucieka Dla ciebie i dlatego jest bardzo bezpieczniejszy.

subprocess.call(['ping', 'localhost'])
157
Nicolas Gervais 24 luty 2020, 01:01
import os
cmd = 'ls -al'
os.system(cmd)

Jeśli chcesz zwrócić wyniki polecenia, możesz użyć {{x0 }}. Jednak jest to niedozwolone od wersji 2.6 na korzyść moduł subprocesowy , które inne odpowiedzi dobrze pokryły.

151
Patrick M 26 styczeń 2016, 16:53

Zawsze używam fabric dla tych rzeczy takich jak:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Ale to wydaje się być dobrym narzędziem: sh (interfejs subprocessów Python).

Spójrz na przykład:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
79
Peter Mortensen 29 listopad 2019, 21:47

Ze standardową biblioteką

Użyj moduł subprocess (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

Jest to zalecany standardowy sposób. Jednak bardziej skomplikowane zadania (rury, wyjście, wejście itp.) Może być nudny do konstruowania i zapisu.

Uwaga w wersji Pythona: Jeśli nadal używasz Python 2, subprocess .Call działa w podobny sposób.

PROTIP: SHLEX.SPLIT może pomóc w analizie Polecenie dla call, call i innych funkcji subprocess w przypadku nie chcesz (lub nie możesz!) Podaj im w formie list:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Z zależnościami zewnętrznymi

Jeśli nie masz nic przeciwko zewnętrznym zależnościom, użyj Plummum:

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

Jest to najlepszy subprocess}. To działa między platformą, tj. Działa zarówno na systemach Windows, jak i UNIX. Zainstaluj według pip install plumbum.

Inną popularną biblioteką jest sh:

from sh import ifconfig
print(ifconfig('wlan0'))

Jednak sh upuścił obsługę systemu Windows, więc nie jest tak niesamowite, jak kiedyś. Zainstaluj według pip install sh.

79
6 revs, 2 users 79% 29 listopad 2019, 21:54

Sprawdź też bibliotekę Python "PExpect".

Umożliwia interaktywne sterowanie zewnętrznymi programami / poleceniami, nawet ssh, FTP, Telnet itp. Możesz po prostu wpisać coś w rodzaju:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')
77
Peter Mortensen 28 maj 2017, 23:02

Jeśli potrzebujesz wyjścia z polecenia, które dzwonisz, Następnie możesz użyć subprocess.Check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Należy również zwrócić uwagę na parametr powłoki.

Jeśli skorupa jest True, określone polecenie zostanie wykonane przez powłokę. Może to być przydatne, jeśli używasz Pythona przede wszystkim do ulepszonego przepływu sterowania, oferuje ponad większość skorup systemowych i nadal chce wygodnego dostępu do innych funkcji powłoki, takich jak rury powłoki, nazwa Dzikie nazwy wieloznaczne, rozbudowa zmiennej środowiska i rozbudowa ~ do domu użytkownika informator. Należy jednak pamiętać, że sam Python oferuje wdrożenia wielu funkcji podobnych do powłoki (w szczególności, glob, fnmatch, os.walk(), {x4}}, os.path.expandvars() i os.path.expanduser() {X6}}).

75
Peter Mortensen 3 czerwiec 2018, 20:18

W ten sposób prowadzę moje polecenia. Ten kod ma wszystko, czego potrzebujesz

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()
59
Usman Khan 28 październik 2012, 05:44

Aktualizacja:

subprocess.run jest zalecanym podejściem AS Of Python 3.5 Jeśli Twój kod nie musi utrzymywać zgodności z wcześniejszymi wersjami Python. Jest bardziej spójny i oferuje podobne łatwość użytkowania jako wysłannik. (Rurociągi nie jest jednak proste. Zobacz To pytanie, jak.)

Oto kilka przykładów z Dokumentacja.

Uruchom proces:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Podnieś na nieudany bieg:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Wyjście przechwytywania:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Oryginalna odpowiedź:

Polecam próbowanie Envoy. Jest to owijka dla subprocess, co z kolei ma na celu zastąpienie starsze moduły i Funkcje. Envoy jest subprocess dla ludzi.

Przykład użycie z Readme:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Rury też wokół:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]
58
Peter Mortensen 29 listopad 2019, 21:52

Użyj Subprocess .

... lub dla bardzo prostego polecenia:

import os
os.system('cat testfile')
48
Peter Mortensen 29 listopad 2019, 21:39

Wywołanie zewnętrznego polecenia w Pythonie

Proste, użyj subprocess.run, co zwraca obiekt CompletedProcess:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Czemu?

Podobnie jak w Pythonie 3.5, dokumentacja zaleca subprocess.run:

Zalecane podejście do wywołania podprocesów jest użycie funkcji RUN () dla wszystkich przypadków użytkowania, które mogą sobie poradzić. W przypadku bardziej zaawansowanych przypadków użycia, podstawowy interfejs popen może być używany bezpośrednio.

Oto przykład najprostszego możliwego wykorzystania - i robi dokładnie, zaraz:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run czeka, aż polecenie pomyślnie zakończyć, a następnie zwróci obiekt CompletedProcess. Zamiast tego może podnieść TimeoutExpired (jeśli dasz mu argument timeout=) lub CalledProcessError (jeśli nie powiedzie się i przechodzisz check=True).

Jak można wywnioskować z powyższego przykładu, Stdout i Stderr są domyślnie pobierane do własnego stdout i stderr.

Możemy sprawdzać zwrócony obiekt i zobaczyć polecenie, które zostało podane i zwrotne:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Wyjście do przechwytywania

Jeśli chcesz uchwycić wyjście, możesz przejść subprocess.PIPE do odpowiedniego stderr lub stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Uważam to za interesujące i nieznacznie sprzeciw, że informacje o wersji zostaną umieszczone na stderr zamiast stdout).

Prześlij listę poleceń

Można łatwo poruszać się z ręcznie dostarczając ciągiem komend (jak pytanie sugeruje), aby zapewnić ciąg programowo programowo. Nie buduj ciągów programowo. Jest to potencjalny problem bezpieczeństwa. Lepiej założyć, że nie ufasz wejściem.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Uwaga, tylko args powinna być przekazana pozycyjnie.

Pełny podpis

Oto rzeczywista podpis w źródle i jak pokazano help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargs i kwargs są podawane do konstruktora Popen. input może być ciągiem bajtów (lub Unicode, jeśli określa kodowanie lub universal_newlines=True), który będzie zniszczony do STDIN subprocess.

Dokumentacja opisuje timeout= i check=True lepiej niż mogłem:

Argument limitu czasu jest przekazywany do Popen.comMunmy (). Jeśli limit czasu wygasa, proces dzieci zostanie zabity i czekał na. Wyjątek limitu czasu zostanie ponownie podniesiony po zakończeniu procesu dziecka.

Jeśli sprawdzenie jest prawdziwe, a proces wyjściowy z kodem wyjścia niezerowy, zostanie podniesiony wyjątek CalleProcesSerror. Atrybuty tego wyjątku przytrzymują argumenty, kod wyjścia i stdder i stderr, jeśli zostały przechwycone.

I ten przykład dla check=True jest lepszy niż jeden, który mógłbym wymyślić:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Rozszerzony podpis

Oto rozszerzony podpis, jak podany w dokumentacji:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Zauważ, że wskazuje, że tylko lista argsów powinna być przekazywana pozycyjnie. Więc przekazać pozostałe argumenty jako argumenty słów kluczowych.

Popen

Kiedy użyj Popen zamiast tego? Walczyłbym, aby znaleźć przypadek użytkowania oparty na argumentach. Bezpośrednie wykorzystanie Popen byłoby jednak zapewnienie dostępu do swoich metod, w tym poll, "send_signal", "zakończenie" i "czekać".

Oto podpis Popen jako podany w źródło . Myślę, że jest to najbardziej precyzyjna enkapsulacja informacji (w przeciwieństwie do help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Ale więcej pouczające jest Dokumentacja Popen:

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Uruchom program potomny w nowym procesie. W POSIX, klasa używa zachowania podobnego do os.execvp () do wykonania programu potomnego. W systemie Windows klasa używa funkcji Windows CreateProcess (). Argumenty dla Popena są następujące.

Zrozumienie pozostałej dokumentacji na Popen zostanie pozostawiona jako ćwiczenie dla czytelnika.

39
Aaron Hall 18 październik 2017, 16:37

os.system jest w porządku, ale rodzaj przestojów. Nie jest również bardzo bezpieczny. Zamiast tego spróbuj subprocess. subprocess Nie nazywa się bezpośrednio i jest zatem bardziej bezpieczny niż os.system.

Uzyskaj więcej informacji Oto.

38
Dimitris Fasarakis Hilliard 10 grudzień 2016, 13:25

Istnieje również Plummum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns
35
stuckintheshuck 10 październik 2014, 17:41

Może to być proste:

import os
cmd = "your command"
os.system(cmd)
30
Samadi Salahedine 8 czerwiec 2018, 12:06

Posługiwać się:

import os

cmd = 'ls -al'

os.system(cmd)

OS - ten moduł zapewnia przenośny sposób korzystania z funkcjonalności zależnej od systemu operacyjnego.

Dla funkcji więcej os, Tutaj jest dokumentacją.

29
Peter Mortensen 28 maj 2017, 23:05

Bardzo lubię Shell_Command dla jego prostoty. Jest zbudowany na górze modułu podprocess.

Oto przykład z dokumentacji:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0
28
Peter Mortensen 29 listopad 2019, 21:49

os.system nie pozwala na przechowywanie wyników, więc jeśli chcesz przechowywać wyniki na jakiejś liście lub coś, a subprocess.call działa.

24
Peter Mortensen 29 listopad 2019, 21:48

subprocess.check_call jest wygodne, jeśli nie chcesz przetestować wartości powrotnych. Rzuca wyjątek na każdym błędzie.

22
cdunn2001 18 styczeń 2011, 19:21

Mam tendencję do używania subprocess wraz z shlex (do obsługi ucieczce z cudzysłowami ) :

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)
22
Emil Stenström 30 kwiecień 2014, 14:37

Bezwstydna wtyczka, napisałem bibliotekę do tego: P https://github.com/ouqp/shell.py

Na razie jest to w zasadzie owijka na popen i Shillex. Obsługuje również polecenia rurociągowe, dzięki czemu można łatwiejsze w Pythonie. Więc możesz robić takie rzeczy jak:

ex('echo hello shell.py') | "awk '{print $2}'"
17
houqp 1 maj 2014, 20:49

W systemie Windows można po prostu zaimportować moduł {X0}} i uruchom komendy zewnętrzne, dzwoniąc subprocess.Popen(), subprocess.Popen().communicate() i subprocess.Popen().wait() jak poniżej:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Wynik:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K
17
Peter Mortensen 28 maj 2017, 23:08

Możesz użyć Popen, a następnie możesz sprawdzić status procedury:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Sprawdź subprocess.popen.

16
Peter Mortensen 28 maj 2017, 23:01