Saya ingin menulis fungsi yang akan menjalankan perintah shell dan mengembalikan hasilnya sebagai string , tidak peduli, apakah itu pesan kesalahan atau sukses. Saya hanya ingin mendapatkan hasil yang sama dengan yang saya dapatkan dengan baris perintah.
Apa yang akan menjadi contoh kode yang akan melakukan hal seperti itu?
Sebagai contoh:
def run_command(cmd):
# ??????
print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
python
shell
subprocess
Cahaya Perak
sumber
sumber
Jawaban:
Jawaban untuk pertanyaan ini tergantung pada versi Python yang Anda gunakan. Pendekatan paling sederhana adalah dengan menggunakan
subprocess.check_output
fungsi:check_output
menjalankan satu program yang hanya menggunakan argumen sebagai input. 1 Ini mengembalikan hasil persis seperti yang dicetakstdout
. Jika Anda perlu menulis inputstdin
, lanjutkan ke bagianrun
atauPopen
. Jika Anda ingin menjalankan perintah shell yang kompleks, lihat catatanshell=True
di akhir jawaban ini.The
check_output
fungsi bekerja pada hampir semua versi Python masih digunakan secara luas (2.7+). 2 Tetapi untuk versi yang lebih baru, ini bukan lagi pendekatan yang direkomendasikan.Versi modern Python (3.5 atau lebih tinggi):
run
Jika Anda menggunakan Python 3.5 atau lebih tinggi, dan tidak perlu kompatibilitas ke belakang , fungsi baru
run
disarankan. Ini menyediakan API tingkat tinggi yang sangat umum untuksubprocess
modul. Untuk menangkap hasil dari suatu program, berikansubprocess.PIPE
tanda padastdout
argumen kata kunci. Kemudian aksesstdout
atribut dariCompletedProcess
objek yang dikembalikan :Nilai kembali adalah
bytes
objek, jadi jika Anda menginginkan string yang tepat, Anda harus melakukannyadecode
. Dengan asumsi proses yang dipanggil mengembalikan string yang dikodekan UTF-8:Ini semua dapat dikompresi menjadi satu-liner:
Jika Anda ingin meneruskan input ke proses
stdin
, berikanbytes
objek keinput
argumen kata kunci:Anda dapat menangkap kesalahan dengan meneruskan
stderr=subprocess.PIPE
(capture toresult.stderr
) ataustderr=subprocess.STDOUT
(capture toresult.stdout
bersama dengan output reguler). Ketika keamanan tidak menjadi masalah, Anda juga dapat menjalankan perintah shell yang lebih kompleks dengan melewatishell=True
seperti yang dijelaskan dalam catatan di bawah ini.Ini menambah sedikit kompleksitas, dibandingkan dengan cara lama dalam melakukan sesuatu. Tetapi saya pikir ini sepadan dengan hasilnya: sekarang Anda dapat melakukan hampir semua hal yang perlu Anda lakukan dengan
run
fungsi itu saja.Versi Python yang lebih lama (2.7-3.4):
check_output
Jika Anda menggunakan versi Python yang lebih lama, atau membutuhkan kompatibilitas mundur sederhana, Anda mungkin dapat menggunakan
check_output
fungsi seperti dijelaskan secara singkat di atas. Ini telah tersedia sejak Python 2.7.Dibutuhkan argumen yang sama seperti
Popen
(lihat di bawah), dan mengembalikan string yang berisi keluaran program. Awal dari jawaban ini memiliki contoh penggunaan yang lebih rinci. Dalam Python 3.5 dan lebih tinggi,check_output
setara dengan mengeksekusirun
dengancheck=True
danstdout=PIPE
, dan mengembalikanstdout
atribut saja.Anda dapat melewati
stderr=subprocess.STDOUT
untuk memastikan bahwa pesan kesalahan termasuk dalam output kembali - tetapi dalam beberapa versi Python lewatstderr=subprocess.PIPE
untukcheck_output
dapat menyebabkan deadlock . Ketika keamanan tidak menjadi masalah, Anda juga dapat menjalankan perintah shell yang lebih kompleks dengan melewatishell=True
seperti yang dijelaskan dalam catatan di bawah ini.Jika Anda perlu pipa dari
stderr
mengirim atau mengirim input ke proses,check_output
tidak akan sesuai dengan tugas. LihatPopen
contoh di bawah ini dalam kasus itu.Aplikasi kompleks & versi lama Python (2.6 dan di bawah):
Popen
Jika Anda memerlukan kompatibilitas mundur yang dalam, atau jika Anda membutuhkan fungsionalitas yang lebih canggih daripada yang
check_output
disediakan, Anda harus bekerja secara langsung dengannyaPopen
objek, yang merangkum API tingkat rendah untuk subproses.The
Popen
konstruktor menerima baik perintah tunggal tanpa argumen, atau daftar yang berisi perintah sebagai pos pertama, diikuti oleh sejumlah argumen, masing-masing sebagai bagian yang terpisah dalam daftar.shlex.split
dapat membantu mem-parsing string ke dalam daftar yang diformat dengan tepat.Popen
benda juga menerima a sejumlah argumen yang berbeda untuk manajemen IO proses dan konfigurasi tingkat rendah.Untuk mengirim input dan menangkap output,
communicate
hampir selalu metode yang disukai. Seperti dalam:Atau
Jika Anda mengatur
stdin=PIPE
,communicate
juga memungkinkan Anda untuk mengirimkan data ke proses melaluistdin
:Catatan Aaron Hall jawaban , yang menunjukkan bahwa pada beberapa sistem, Anda mungkin perlu set
stdout
,stderr
danstdin
semua untukPIPE
(atauDEVNULL
) untuk mendapatkancommunicate
pekerjaan sama sekali.Dalam beberapa kasus yang jarang terjadi, Anda mungkin perlu menangkap keluaran real-time yang kompleks. Jawaban Vartec menunjukkan jalan ke depan, tetapi metode selain
communicate
rentan terhadap kebuntuan jika tidak digunakan dengan hati-hati.Seperti semua fungsi di atas, ketika keamanan tidak menjadi perhatian, Anda dapat menjalankan perintah shell yang lebih kompleks dengan melewati
shell=True
.Catatan
1. Menjalankan perintah shell: the
shell=True
argumenBiasanya, setiap panggilan ke
run
,check_output
, atauPopen
konstruktor mengeksekusi program tunggal . Itu berarti tidak ada pipa bergaya bash mewah. Jika Anda ingin menjalankan perintah shell yang kompleks, Anda bisa meneruskannyashell=True
, yang didukung oleh ketiga fungsi.Namun, hal itu menimbulkan masalah keamanan . Jika Anda melakukan sesuatu lebih dari skrip ringan, Anda mungkin lebih baik memanggil setiap proses secara terpisah, dan meneruskan output dari masing-masing sebagai input ke yang berikutnya, melalui
Atau
Godaan untuk menghubungkan langsung pipa kuat; menolaknya. Kalau tidak, Anda mungkin akan melihat kebuntuan atau harus melakukan hal-hal seperti ini .
2. Pertimbangan Unicode
check_output
mengembalikan sebuah string dengan Python 2, tetapi sebuahbytes
objek dengan Python 3. Perlu mengambil waktu sejenak untuk belajar tentang unicode jika Anda belum melakukannya.sumber
check_output()
dancommunicate()
Anda harus menunggu sampai proses selesai, denganpoll()
Anda mendapatkan output yang datang. Sangat tergantung apa yang Anda butuhkan.out
adalah tipe<class 'bytes'>
untuk saya. Untuk mendapatkan output sebagai string, saya harus mendekodekannya sebelum mencetak seperti ini:out.decode("utf-8")
shell=True
? Ini bekerja untuk saya. Anda tidak perlushlex.split
ketika lulusshell=True
.shlex.split
adalah untuk perintah non-shell. Saya pikir saya akan mengambil sedikit karena ini mengeruhkan air.universal_newlines=True
yang memungkinkan Anda untuk masuk dan keluar string Unicode dalam pengkodean default sistem. Dalam 3.7 ini diganti namanya menjadi lebih masuk akaltext=True
.encoding
parametersubprocess.run
alih-alih menggunakanresult.stdout.decode('utf-8')
, Anda bisa menggunakansubprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
.Ini jauh lebih mudah, tetapi hanya berfungsi di Unix (termasuk Cygwin) dan Python2.7.
Ini mengembalikan tuple dengan (return_value, output).
Untuk solusi yang berfungsi di Python2 dan Python3, gunakan
subprocess
modul sebagai gantinya:sumber
Sesuatu seperti itu:
Catatan, bahwa saya mengarahkan stderr ke stdout, mungkin tidak persis seperti yang Anda inginkan, tetapi saya juga ingin pesan kesalahan.
Fungsi ini menghasilkan baris demi baris saat mereka datang (biasanya Anda harus menunggu sampai selesai untuk mendapatkan output secara keseluruhan).
Untuk kasus Anda, penggunaannya adalah:
sumber
wait
dancall
fungsi.PIPE
nilaistdin
dan tutup file itu segera setelahPopen
kembali.retcode
is0
. Cek seharusnyaif retcode is not None
. Anda tidak harus menghasilkan string kosong (bahkan baris kosong setidaknya satu simbol '\ n'):if line: yield line
. Panggilp.stdout.close()
di akhir..readlines()
tidak akan kembali sampai semua output dibaca dan karena itu rusak untuk output besar yang tidak sesuai dengan memori. Juga untuk menghindari data buffered yang hilang setelah subproses keluar harus ada analogif retcode is not None: yield from p.stdout.readlines(); break
Jawaban Vartec tidak membaca semua baris, jadi saya membuat versi yang melakukannya:
Penggunaannya sama dengan jawaban yang diterima:
sumber
return iter(p.stdout.readline, b'')
alih-alih loop sementarap.stdout.readline()
dapat mengembalikan output buffered yang tidak kosong sebelumnya bahkan jika proses anak sudah keluar (p.poll()
tidakNone
).Ini adalah solusi rumit namun super sederhana yang bekerja dalam banyak situasi:
File sementara (di sini adalah tmp) dibuat dengan output dari perintah dan Anda dapat membaca darinya output yang Anda inginkan.
Catatan tambahan dari komentar: Anda dapat menghapus file tmp dalam hal pekerjaan satu kali. Jika Anda perlu melakukan ini beberapa kali, tidak perlu menghapus tmp.
sumber
mktemp
membuatnya berfungsi dalam situasi berulir yang saya kiraos.remove('tmp')
untuk membuatnya "fileless".Saya memiliki masalah yang sama tetapi menemukan cara yang sangat sederhana untuk melakukan ini:
Semoga ini bisa membantu
Catatan: Solusi ini spesifik untuk Python3 karena
subprocess.getoutput()
tidak berfungsi di Python2sumber
Anda dapat menggunakan perintah berikut untuk menjalankan perintah shell. Saya telah menggunakannya di ubuntu.
Catatan: Ini sudah tidak digunakan lagi sejak python 2.6. Sekarang Anda harus menggunakan
subprocess.Popen
. Di bawah ini adalah contohnyasumber
os.popen()
tidak digunakan lagi dalam Python 2.6, tetapi ini tidak ditinggalkan dalam Python 3.x, karena dalam 3.x itu diimplementasikan menggunakansubprocess.Popen()
.Mileage Anda Mungkin Bervariasi, saya mencoba memutar @ senderle pada solusi Vartec di Windows pada Python 2.6.5, tetapi saya mendapatkan kesalahan, dan tidak ada solusi lain yang berfungsi. Kesalahan saya adalah:
WindowsError: [Error 6] The handle is invalid
.Saya menemukan bahwa saya harus menetapkan PIPE ke setiap pegangan untuk mendapatkannya mengembalikan output yang saya harapkan - berikut ini bekerja untuk saya.
dan panggil seperti ini, (
[0]
dapatkan elemen pertama dari tuple,stdout
):Setelah belajar lebih banyak, saya yakin saya perlu argumen pipa ini karena saya sedang mengerjakan sistem kustom yang menggunakan pegangan berbeda, jadi saya harus langsung mengendalikan semua std's.
Untuk menghentikan popup konsol (dengan Windows), lakukan ini:
sumber
DEVNULL
alih - alihsubprocess.PIPE
jika Anda tidak menulis / membaca dari pipa jika tidak, Anda dapat menggantung proses anak.Saya memiliki rasa yang sedikit berbeda dari masalah yang sama dengan persyaratan berikut:
kata kunci 'hasil' di atas
Saya telah menggabungkan dan mengubah jawaban sebelumnya untuk menghasilkan yang berikut:
Kode ini akan dieksekusi sama dengan jawaban sebelumnya:
sumber
p.poll()
tanpa tidur di antara panggilan, kami akan membuang siklus CPU dengan memanggil fungsi ini jutaan kali. Sebagai gantinya, kita "menekan" loop kita dengan memberi tahu OS bahwa kita tidak perlu diganggu untuk 1/10 detik berikutnya, sehingga dapat melakukan tugas-tugas lain. (Mungkin p.poll () tidur juga, membuat pernyataan tidur kita berlebihan).Membagi perintah awal untuk yang
subprocess
mungkin rumit dan rumit.Gunakan
shlex.split()
untuk membantu diri Anda sendiri.Perintah sampel
git log -n 5 --since "5 years ago" --until "2 year ago"
Kode
Tanpa
shlex.split()
kode akan terlihat sebagai berikutsumber
shlex.split()
adalah suatu kemudahan, terutama jika Anda tidak tahu bagaimana tepatnya mengutip dalam shell berfungsi; tetapi secara manual mengubah string ini ke daftar['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']
tidak sulit sama sekali jika Anda mengerti mengutip.Jika Anda perlu menjalankan perintah shell pada banyak file, ini berhasil bagi saya.
Sunting: Baru melihat solusi Max Persson dengan saran JF Sebastian. Pergi ke depan dan memasukkan itu.
sumber
Popen
menerima string, tetapi kemudian Anda perlushell=True
, atau daftar argumen, dalam hal ini Anda harus meneruskan['nm', filename]
bukannya string. Yang terakhir lebih disukai karena shell menambah kompleksitas tanpa memberikan nilai apa pun di sini. Melewati string tanpashell=True
tampaknya bekerja pada Windows, tetapi itu bisa berubah di versi Python berikutnya.Menurut @senderle, jika Anda menggunakan python3.6 seperti saya:
Akan bertindak persis seperti Anda menjalankan perintah di bash
sumber
check=True, universal_newlines=True
. Dengan kata lainsubprocess.run()
sudah melakukan semua kode Anda.Jika Anda menggunakan
subprocess
modul python, Anda dapat menangani STDOUT, STDERR dan mengembalikan kode perintah secara terpisah. Anda dapat melihat contoh untuk implementasi pemanggil perintah lengkap. Tentu saja Anda dapat memperpanjangnyatry..except
jika Anda mau.Fungsi di bawah ini mengembalikan kode STDOUT, STDERR, dan Return sehingga Anda dapat menanganinya di skrip lain.
sumber
subprocess.run()
. Jangan menemukan kembali roda.mis., jalankan ('ls -ahl') yang membedakan tiga / empat kemungkinan pengembalian dan platform OS:
fungsi di bawah ini
sumber
Keluaran dapat diarahkan ke file teks dan kemudian membacanya kembali.
sumber
stdout=temp_file
?ecls.exe
tampaknya menyebarkan alat baris perintah lain, sehingga cara sederhana kadang-kadang tidak berfungsi.baru saja menulis skrip bash kecil untuk melakukan ini menggunakan ikal
https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5
sumber