Bagaimana Anda memanggil perintah eksternal (seolah-olah saya mengetiknya di shell Unix atau command prompt Windows) dari dalam skrip Python?
Bagaimana Anda memanggil perintah eksternal (seolah-olah saya mengetiknya di shell Unix atau command prompt Windows) dari dalam skrip Python?
Jawaban:
Lihatlah modul subproses di perpustakaan standar:
import subprocess
subprocess.run(["ls", "-l"])
Keuntungan dari subprocess
vs system
adalah bahwa hal itu lebih fleksibel (Anda bisa mendapatkan stdout
, stderr
, "nyata" kode status, penanganan kesalahan yang lebih baik, dll ...).
The dokumentasi resmi merekomendasikan subprocess
modul atas alternatif os.system()
:
The
subprocess
Modul menyediakan fasilitas yang lebih kuat untuk pemijahan proses baru dan mengambil hasil mereka; menggunakan modul itu lebih baik daripada menggunakan fungsi ini [os.system()
].
Bagian Mengganti Fungsi yang Lebih Lama dengan bagian Modul subproses dalam subprocess
dokumentasi mungkin memiliki beberapa resep yang bermanfaat.
Untuk versi Python sebelum 3.5, gunakan call
:
import subprocess
subprocess.call(["ls", "-l"])
shell=True
agar bisa berfungsi.
shell=True
, untuk tujuan ini Python datang dengan os.path.expandvars . Dalam kasus Anda, Anda dapat menulis: os.path.expandvars("$PATH")
. @SethMMorton harap pertimbangkan kembali komentar Anda -> Mengapa tidak menggunakan shell = True
for
lingkaran, bagaimana cara melakukannya tanpa memblokir skrip python saya? Saya tidak peduli dengan output dari perintah saya hanya ingin menjalankan banyak dari mereka.
subprocess
kapan shell=False
, maka gunakan shlex.split
cara mudah untuk melakukan ini docs.python.org/2/library/shlex.html#shlex.split
Berikut ini ringkasan cara memanggil program eksternal serta kelebihan dan kekurangan masing-masing:
os.system("some_command with args")
meneruskan perintah dan argumen ke shell sistem Anda. Ini bagus karena Anda benar-benar dapat menjalankan banyak perintah sekaligus dengan cara ini dan mengatur pipa dan pengalihan input / output. Sebagai contoh:
os.system("some_command < input_file | another_command > output_file")
Namun, sementara ini mudah, Anda harus secara manual menangani keluarnya karakter shell seperti spasi, dll. Di sisi lain, ini juga memungkinkan Anda menjalankan perintah yang hanya perintah shell dan bukan program eksternal sebenarnya. Lihat dokumentasi .
stream = os.popen("some_command with args")
akan melakukan hal yang sama seperti os.system
kecuali bahwa itu memberi Anda objek seperti file yang dapat Anda gunakan untuk mengakses input / output standar untuk proses itu. Ada 3 varian popen lainnya yang semuanya menangani i / o sedikit berbeda. Jika Anda melewatkan semuanya sebagai string, maka perintah Anda diteruskan ke shell; jika Anda melewati mereka sebagai daftar maka Anda tidak perlu khawatir akan melarikan diri apa pun. Lihat dokumentasi .
The Popen
kelas dari subprocess
modul. Ini dimaksudkan sebagai pengganti os.popen
tetapi memiliki kelemahan karena sedikit lebih rumit karena begitu komprehensif. Misalnya, Anda akan mengatakan:
print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
dari pada:
print os.popen("echo Hello World").read()
tetapi menyenangkan untuk memiliki semua opsi di sana dalam satu kelas terpadu, bukan 4 fungsi popen berbeda. Lihat dokumentasi .
The call
fungsi dari subprocess
modul. Ini pada dasarnya seperti Popen
kelas dan mengambil semua argumen yang sama, tetapi hanya menunggu sampai perintah selesai dan memberi Anda kode kembali. Sebagai contoh:
return_code = subprocess.call("echo Hello World", shell=True)
Lihat dokumentasi .
Jika Anda menggunakan Python 3.5 atau lebih baru, Anda dapat menggunakan subprocess.run
fungsi baru , yang sangat mirip di atas tetapi bahkan lebih fleksibel dan mengembalikan CompletedProcess
objek ketika perintah selesai dijalankan.
Modul os juga memiliki semua fungsi fork / exec / spawn yang Anda miliki dalam program C, tapi saya tidak merekomendasikan untuk menggunakannya secara langsung.
The subprocess
Modul mungkin harus apa yang Anda gunakan.
Akhirnya perlu diketahui bahwa untuk semua metode di mana Anda melewati perintah terakhir yang akan dieksekusi oleh shell sebagai string dan Anda bertanggung jawab untuk menghindarinya. Ada implikasi keamanan serius jika ada bagian dari string yang Anda lewati tidak dapat dipercaya sepenuhnya. Misalnya, jika pengguna memasukkan beberapa bagian string. Jika Anda tidak yakin, gunakan saja metode ini dengan konstanta. Untuk memberi Anda sedikit implikasi, pertimbangkan kode ini:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
dan bayangkan bahwa pengguna memasukkan sesuatu "mama saya tidak mencintaiku &&rm -rf /" yang dapat menghapus seluruh sistem file.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
subprocess.run(..)
,, apa sebenarnya yang dilakukan "Ini tidak menangkap stdout atau stderr secara default." berarti? Bagaimana dengan subprocess.check_output(..)
dan STDERR?
echo
depan string dilewatkan Popen
? Jadi perintah penuhnya adalah echo my mama didnt love me && rm -rf /
.
subprocess.run()
saudara kandungnya saja subprocess.check_call()
. Untuk kasus di mana ini tidak cukup, lihat subprocess.Popen()
. os.popen()
mungkin seharusnya tidak disebutkan sama sekali, atau datang bahkan setelah "retas kode fork / exec / spawn Anda sendiri".
Implementasi yang khas:
import subprocess
p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
print line,
retval = p.wait()
Anda bebas melakukan apa yang Anda inginkan dengan stdout
data di dalam pipa. Bahkan, Anda bisa dengan mudah menghilangkan parameter tersebut ( stdout=
dan stderr=
) dan itu akan berperilaku seperti os.system()
.
.readlines()
membaca semua baris sekaligus yaitu, itu memblokir sampai subproses keluar (menutup ujung pipa). Untuk membaca secara real time (jika tidak ada masalah buffering) Anda bisa:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(catatan: tidak ada s
di akhir) tidak akan melihat data apa pun sampai anak mengisi buffernya. Jika anak tidak menghasilkan banyak data maka hasilnya tidak akan secara real time. Lihat alasan kedua di T: Mengapa tidak menggunakan pipa (popen ())? . Beberapa solusi disediakan dalam jawaban ini (harap, pty, stdbuf)
Popen
untuk tugas-tugas sederhana. Ini juga tidak perlu ditentukan shell=True
. Coba salah satu subprocess.run()
jawabannya.
Beberapa petunjuk tentang melepaskan proses anak dari proses pemanggilan (memulai proses anak di latar belakang).
Misalkan Anda ingin memulai tugas panjang dari skrip CGI. Artinya, proses anak harus hidup lebih lama dari proses eksekusi skrip CGI.
Contoh klasik dari dokumentasi modul subproses adalah:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
Idenya di sini adalah bahwa Anda tidak ingin menunggu di baris 'panggilan subproses' sampai longtask.py selesai. Tetapi tidak jelas apa yang terjadi setelah baris 'kode lagi di sini' dari contoh.
Platform target saya adalah FreeBSD, tetapi pengembangannya pada Windows, jadi saya menghadapi masalah pada Windows terlebih dahulu.
Di Windows (Windows XP), proses induk tidak akan selesai sampai longtask.py telah menyelesaikan pekerjaannya. Bukan apa yang Anda inginkan dalam skrip CGI. Masalahnya tidak spesifik untuk Python; dalam komunitas PHP masalahnya sama.
Solusinya adalah dengan melewati DETACHED_PROCESS Flag Pembuatan Proses ke fungsi CreateProcess yang mendasarinya di Windows API. Jika Anda telah menginstal pywin32, Anda dapat mengimpor flag dari modul win32process, jika tidak, Anda harus mendefinisikannya sendiri:
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/ * UPD 2015.10.27 @eryksun dalam komentar di bawah ini mencatat, bahwa tanda yang benar secara semantik adalah CREATE_NEW_CONSOLE (0x00000010) * /
Pada FreeBSD kami memiliki masalah lain: ketika proses induk selesai, itu menyelesaikan proses anak juga. Dan itu juga bukan yang Anda inginkan dalam skrip CGI. Beberapa percobaan menunjukkan bahwa masalahnya sepertinya ada pada sharing sys.stdout. Dan solusi kerjanya adalah sebagai berikut:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Saya belum memeriksa kode di platform lain dan tidak tahu alasan perilaku di FreeBSD. Jika ada yang tahu, silakan bagikan ide Anda. Googling untuk memulai proses latar belakang dengan Python belum menjelaskan apa pun.
DETACHED_PROCESS
dalam creationflags
menghindari ini dengan mencegah anak dari mewarisi atau membuat konsol. Jika Anda menginginkan konsol baru, gunakan CREATE_NEW_CONSOLE
(0x00000010).
os.devnull
karena beberapa program konsol keluar dengan kesalahan sebaliknya. Buat konsol baru saat Anda ingin proses anak berinteraksi dengan pengguna secara bersamaan dengan proses induk. Akan membingungkan untuk mencoba melakukan keduanya dalam satu jendela.
import os
os.system("your command")
Perhatikan bahwa ini berbahaya, karena perintahnya tidak dibersihkan. Saya serahkan kepada Anda untuk google untuk dokumentasi yang relevan pada modul 'os' dan 'sys'. Ada banyak fungsi (exec * dan spawn *) yang akan melakukan hal serupa.
subprocess
sebagai solusi yang sedikit lebih fleksibel dan portabel. Menjalankan perintah eksternal tentu saja secara inheren tidak dapat diangkut (Anda harus memastikan perintah itu tersedia pada setiap arsitektur yang Anda butuhkan untuk mendukung) dan meneruskan input pengguna sebagai perintah eksternal secara inheren tidak aman.
Saya akan merekomendasikan menggunakan modul subproses daripada os.system karena shell melarikan diri untuk Anda dan karenanya jauh lebih aman.
subprocess.call(['ping', 'localhost'])
subprocess
kapan shell=False
, maka gunakan shlex.split
cara mudah untuk melakukan ini docs.python.org/2/library/shlex.html#shlex.split ( itu cara yang disarankan menurut docs docs.python.org/2/library/subprocess.html#popen-constructor )
import os
cmd = 'ls -al'
os.system(cmd)
Jika Anda ingin mengembalikan hasil perintah, Anda dapat menggunakan os.popen
. Namun, ini sudah tidak berlaku lagi sejak versi 2.6 mendukung modul subproses , yang telah dijawab dengan baik oleh jawaban lain.
Ada banyak pustaka yang berbeda yang memungkinkan Anda untuk memanggil perintah eksternal dengan Python. Untuk setiap perpustakaan saya telah memberikan deskripsi dan menunjukkan contoh memanggil perintah eksternal. Perintah yang saya gunakan sebagai contoh adalah ls -l
(daftar semua file). Jika Anda ingin mengetahui lebih lanjut tentang perpustakaan yang saya daftarkan dan tautkan dokumentasi untuk masing-masing perpustakaan.
Sumber:
Ini semua perpustakaan:
Semoga ini akan membantu Anda membuat keputusan tentang perpustakaan mana yang akan digunakan :)
subproses
Subprocess memungkinkan Anda untuk memanggil perintah eksternal dan menghubungkannya ke input / output / pipa kesalahan mereka (stdin, stdout, dan stderr). Subprocess adalah pilihan default untuk menjalankan perintah, tetapi terkadang modul lain lebih baik.
subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
os
os digunakan untuk "fungsionalitas tergantung sistem operasi". Itu juga dapat digunakan untuk memanggil perintah eksternal dengan os.system
dan os.popen
(Catatan: Ada juga subprocess.popen). os akan selalu menjalankan shell dan merupakan alternatif sederhana untuk orang yang tidak perlu, atau tidak tahu cara menggunakannya subprocess.run
.
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
SH
sh adalah antarmuka subproses yang memungkinkan Anda memanggil program seolah-olah itu adalah fungsi. Ini berguna jika Anda ingin menjalankan perintah beberapa kali.
sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function
timah hitam
Plumbum adalah pustaka untuk program Python "mirip script". Anda dapat memanggil program seperti fungsi seperti pada sh
. Timah hitam berguna jika Anda ingin menjalankan pipa tanpa cangkang.
ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
harap
pexpect memungkinkan Anda menelurkan aplikasi anak, mengontrolnya dan menemukan pola dalam hasilnya. Ini adalah alternatif yang lebih baik daripada subproses untuk perintah yang mengharapkan tty di Unix.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
kain
fabric adalah pustaka Python 2.5 dan 2.7. Ini memungkinkan Anda untuk menjalankan perintah shell lokal dan jarak jauh. Fabric adalah alternatif sederhana untuk menjalankan perintah dalam secure shell (SSH)
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
utusan
Utusan itu dikenal sebagai "subproses untuk manusia". Ini digunakan sebagai pembungkus kenyamanan di sekitar subprocess
modul.
r = envoy.run("ls -l") # Run command
r.std_out # get output
perintah
commands
berisi fungsi wrapper untuk os.popen
, tetapi telah dihapus dari Python 3 karena subprocess
merupakan alternatif yang lebih baik.
Hasil edit didasarkan pada komentar JF Sebastian.
Saya selalu menggunakan fabric
untuk hal-hal ini seperti:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
Tapi ini tampaknya menjadi alat yang bagus: sh
(Python antarmuka proses) .
Lihatlah sebuah contoh:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
Periksa perpustakaan Python "pexpect" juga.
Hal ini memungkinkan untuk mengendalikan interaktif program / perintah eksternal, bahkan ssh, ftp, telnet, dll. Anda dapat mengetik sesuatu seperti:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
Gunakan modul subproses (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
Ini adalah cara standar yang disarankan. Namun, tugas yang lebih rumit (pipa, output, input, dll.) Dapat membosankan untuk dibangun dan ditulis.
Catatan tentang versi Python: Jika Anda masih menggunakan Python 2, subprocess.call bekerja dengan cara yang sama.
ProTip: shlex.split dapat membantu Anda mem-parsing perintah untuk run
,, call
dan subprocess
fungsi - fungsi lain jika Anda tidak ingin (atau tidak bisa!) Menyediakannya dalam bentuk daftar:
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Jika Anda tidak keberatan dengan ketergantungan eksternal, gunakan timah hitam :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Ini adalah subprocess
pembungkus terbaik . Ini cross-platform, yaitu bekerja pada sistem Windows dan Unix-like. Instal olehpip install plumbum
.
Perpustakaan populer lainnya adalah sh :
from sh import ifconfig
print(ifconfig('wlan0'))
Namun, sh
menjatuhkan dukungan Windows, jadi itu tidak sehebat dulu. Instal oleh pip install sh
.
Jika Anda membutuhkan output dari perintah yang Anda panggil, maka Anda dapat menggunakan 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'
Perhatikan juga parameter shell .
Jika shell
True
, perintah yang ditentukan akan dieksekusi melalui shell. Ini dapat berguna jika Anda menggunakan Python terutama untuk meningkatkan aliran kontrol yang ditawarkannya pada sebagian besar sistem shell dan masih menginginkan akses yang mudah ke fitur shell lainnya seperti pipa shell, wildcard nama file, ekspansi variabel lingkungan, dan perluasan ~ ke rumah pengguna direktori. Namun, catatan bahwa Python sendiri menawarkan implementasi dari banyak shell-seperti fitur (khususnya,glob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, danshutil
).
check_output
membutuhkan daftar daripada string. Jika Anda tidak mengandalkan spasi yang dikutip untuk menjadikan panggilan Anda valid, cara paling sederhana dan paling mudah dibaca untuk melakukannya adalah subprocess.check_output("ls -l /dev/null".split())
.
Ini adalah bagaimana saya menjalankan perintah saya. Kode ini memiliki semua yang Anda butuhkan
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()
subprocess.run
adalah pendekatan yang disarankan pada Python 3.5 jika kode Anda tidak perlu mempertahankan kompatibilitas dengan versi Python sebelumnya. Ini lebih konsisten dan menawarkan kemudahan penggunaan yang sama seperti Utusan. (Pipa tidak sejelas mungkin. Lihat pertanyaan ini untuk caranya .)
Berikut beberapa contoh dari dokumentasi .
Jalankan proses:
>>> subprocess.run(["ls", "-l"]) # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
Naikkan saat gagal dijalankan:
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Capture output:
>>> 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')
Saya sarankan mencoba Utusan . Ini adalah pembungkus untuk subproses, yang pada gilirannya bertujuan untuk menggantikan modul dan fungsi yang lebih lama. Utusan adalah proses bagi manusia.
Contoh penggunaan dari 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
''
Barang pipa sekitar juga:
>>> r = envoy.run('uptime | pbcopy')
>>> r.command
'pbcopy'
>>> r.status_code
0
>>> r.history
[<Response 'uptime'>]
Gunakan subproses .
... atau untuk perintah yang sangat sederhana:
import os
os.system('cat testfile')
os.system
OK, tapi agak tanggal. Ini juga tidak terlalu aman. Sebagai gantinya, cobalah subprocess
. subprocess
tidak memanggil sh secara langsung dan karenanya lebih aman daripada os.system
.
Dapatkan informasi lebih lanjut di sini .
subprocess
tidak menghapus semua masalah keamanan, dan memiliki beberapa masalah sial sendiri.
Memanggil perintah eksternal dengan Python
Sederhana, gunakan subprocess.run
, yang mengembalikan CompletedProcess
objek:
>>> 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)
Pada Python 3.5, dokumentasi merekomendasikan subprocess.run :
Pendekatan yang disarankan untuk menjalankan subproses adalah menggunakan fungsi run () untuk semua kasus penggunaan yang dapat ditangani. Untuk kasus penggunaan yang lebih lanjut, antarmuka Popen yang mendasarinya dapat digunakan secara langsung.
Berikut adalah contoh penggunaan paling sederhana yang mungkin - dan tidak persis seperti yang diminta:
>>> 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
menunggu perintah berhasil diselesaikan, lalu mengembalikan CompletedProcess
objek. Alih-alih itu dapat meningkatkan TimeoutExpired
(jika Anda memberikan timeout=
argumen) atau CalledProcessError
(jika gagal dan Anda lulus check=True
).
Seperti yang Anda simpulkan dari contoh di atas, stdout dan stderr keduanya disalurkan ke stdout dan stderr Anda secara default.
Kita dapat memeriksa objek yang dikembalikan dan melihat perintah yang diberikan dan kode pengembalian:
>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
Jika Anda ingin menangkap output, Anda dapat meneruskan subprocess.PIPE
ke yang sesuai stderr
atau 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''
(Saya menemukan itu menarik dan sedikit berlawanan dengan intuisi bahwa info versi dimasukkan ke stderr bukan stdout.)
Seseorang mungkin dengan mudah berpindah dari menyediakan string perintah secara manual (seperti yang disarankan pertanyaan) ke menyediakan string yang dibuat secara terprogram. Jangan membangun string secara pemrograman. Ini adalah masalah keamanan potensial. Lebih baik untuk menganggap Anda tidak percaya input.
>>> 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'
Catatan, hanya args
harus dilewati secara posisi.
Inilah tanda tangan aktual di sumber dan seperti yang ditunjukkan oleh help(run)
:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
The popenargs
dan kwargs
diberikan kepada Popen
konstruktor. input
dapat berupa serangkaian byte (atau unicode, jika ditentukan penyandian atau universal_newlines=True
) yang akan disalurkan ke stdin subproses.
Dokumentasi menjelaskan timeout=
dan check=True
lebih baik daripada yang saya bisa:
Argumen batas waktu diteruskan ke Popen.communicate (). Jika batas waktu berakhir, proses anak akan dibunuh dan menunggu. Pengecualian TimeoutExpired akan dimunculkan kembali setelah proses anak dihentikan.
Jika check benar, dan proses keluar dengan kode keluar non-nol, pengecualian CalledProcessError akan dimunculkan. Atribut pengecualian itu menyimpan argumen, kode keluar, dan stdout dan stderr jika ditangkap.
dan contoh ini untuk check=True
lebih baik daripada yang saya dapat dengan:
>>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Berikut tanda tangan yang diperluas, seperti yang diberikan dalam dokumentasi:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
Perhatikan bahwa ini menunjukkan bahwa hanya daftar args yang harus dilewati secara posisi. Jadi berikan argumen yang tersisa sebagai argumen kata kunci.
Kapan digunakan Popen
sebagai gantinya? Saya akan berjuang untuk menemukan use case berdasarkan argumen saja. Popen
Namun, penggunaan langsung akan memberi Anda akses ke metode-metodenya, termasuk poll
, 'send_signal', 'terminate', dan 'wait'.
Inilah Popen
tanda tangan seperti yang diberikan dalam sumber . Saya pikir ini adalah enkapsulasi informasi yang paling tepat (sebagai lawan dari 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):
Tapi yang lebih informatif adalah yang Popen
dokumentasi :
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)
Jalankan program anak dalam proses baru. Pada POSIX, kelas menggunakan perilaku seperti os.execvp () - untuk menjalankan program anak. Pada Windows, kelas menggunakan fungsi Windows CreateProcess (). Argumen untuk Popen adalah sebagai berikut.
Memahami dokumentasi yang tersisa Popen
akan dibiarkan sebagai latihan bagi pembaca.
shell=True
atau (lebih baik lagi) melewati perintah sebagai daftar.
Ada juga Timah
>>> 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
Menggunakan:
import os
cmd = 'ls -al'
os.system(cmd)
os - Modul ini menyediakan cara portabel menggunakan fungsionalitas yang tergantung pada sistem operasi.
Untuk lebih banyak os
fungsi, berikut adalah dokumentasi.
Ini bisa sesederhana ini:
import os
cmd = "your command"
os.system(cmd)
Saya cukup suka shell_command karena kesederhanaannya. Itu dibangun di atas modul subproses.
Berikut ini contoh dari dokumentasi:
>>> 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
Ada perbedaan lain di sini yang tidak disebutkan sebelumnya.
subprocess.Popen
mengeksekusi <perintah> sebagai subproses. Dalam kasus saya, saya perlu menjalankan file <a> yang perlu berkomunikasi dengan program lain, <b>.
Saya mencoba subproses, dan eksekusi berhasil. Namun <b> tidak dapat berkomunikasi dengan <a>. Semuanya normal ketika saya menjalankan keduanya dari terminal.
Satu lagi: (CATATAN: kwrite berperilaku berbeda dari aplikasi lain. Jika Anda mencoba yang di bawah ini dengan Firefox, hasilnya tidak akan sama.)
Jika Anda mencoba os.system("kwrite")
, aliran program membeku hingga pengguna menutup kwrite. Untuk mengatasinya saya malah mencoba os.system(konsole -e kwrite)
. Program waktu ini terus mengalir, tetapi kwrite menjadi subproses konsol.
Siapa pun yang menjalankan kwrite bukan menjadi subproses (yaitu di monitor sistem, ia harus muncul di tepi paling kiri dari pohon).
os.system
tidak memungkinkan Anda untuk menyimpan hasil, jadi jika Anda ingin menyimpan hasil dalam beberapa daftar atau sesuatu, sebuah subprocess.call
karya.
Saya cenderung menggunakan subproses bersama dengan shlex (untuk menangani pelolosan string yang dikutip):
>>> 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)
Shameless plug, saya menulis sebuah perpustakaan untuk ini: P https://github.com/houqp/shell.py
Ini pada dasarnya pembungkus popen dan shlex untuk saat ini. Ini juga mendukung perintah perpipaan sehingga Anda dapat melakukan perintah dengan lebih mudah dengan Python. Jadi Anda dapat melakukan hal-hal seperti:
ex('echo hello shell.py') | "awk '{print $2}'"
Di Windows Anda hanya dapat mengimpor subprocess
modul dan menjalankan perintah eksternal dengan memanggil subprocess.Popen()
, subprocess.Popen().communicate()
dan subprocess.Popen().wait()
seperti di bawah ini:
# 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)
Keluaran:
This process detail:
python.exe 604 RDP-Tcp#0 4 5,660 K
Di Linux, jika Anda ingin memanggil perintah eksternal yang akan dieksekusi secara independen (akan tetap berjalan setelah skrip python berakhir), Anda dapat menggunakan antrian sederhana sebagai spooler tugas atau perintah at
Contoh dengan pengumpul tugas:
import os
os.system('ts <your-command>')
Catatan tentang spooler tugas ( ts
):
Anda bisa mengatur jumlah proses bersamaan untuk dijalankan ("slot") dengan:
ts -S <number-of-slots>
Instalasi ts
tidak memerlukan hak admin. Anda dapat mengunduh dan mengompilasinya dari sumber dengan sederhana make
, menambahkannya ke jalur Anda dan selesai.
ts
bukan standar pada setiap distro yang saya tahu, meskipun pointer ke at
agak berguna. Anda mungkin juga harus menyebutkan batch
. Seperti di tempat lain, os.system()
rekomendasi mungkin setidaknya harus menyebutkan bahwa itu subprocess
adalah penggantian yang direkomendasikan.
Anda dapat menggunakan Popen, dan kemudian Anda dapat memeriksa status prosedur:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Lihat subproses.Popen .
Untuk mengambil id jaringan dari OpenStack Neutron :
#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read() /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)
Output dari daftar nova
+--------------------------------------+------------+------+
| ID | Label | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1 | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal | None |
+--------------------------------------+------------+------+
Output cetak (networkId)
27a74fcd-37c0-4789-9414-9531b7e3f126
os.popen()
pada 2016. Skrip Awk dapat dengan mudah diganti dengan kode Python asli.
echo $PATH
dengan menggunakancall(["echo", "$PATH"])
, tetapi itu hanya menggemakan string literal$PATH
daripada melakukan substitusi apa pun. Saya tahu saya bisa mendapatkan variabel lingkungan PATH, tapi saya bertanya-tanya apakah ada cara mudah untuk memiliki perintah berperilaku persis seolah-olah saya telah mengeksekusi di bash.