Jalankan perintah shell dengan Python

65

Saya sedang mempelajari pengujian penetrasi dan pemrograman Python. Saya hanya ingin tahu bagaimana cara menjalankan perintah Linux dengan Python. Perintah yang ingin saya jalankan adalah:

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080

Jika saya hanya menggunakan printPython dan menjalankannya di terminal, apakah akan melakukan hal yang sama seperti mengeksekusi seolah-olah Anda mengetik sendiri dan menekan Enter?

iZodiac
sumber
5
os.sistem dapat melakukan ini.
Foot
2
dan saya pikir bashitu adalah shell yang membengkak ...
mikeserv
3
Dokumen untuk os.systemdirekomendasikan menggunakan subprocessmodul.
jordanm
Apakah Anda memerlukan output dari iptables?
Kira
3
Pertanyaan ini harus dimigrasikan ke Stackoverflow.
www139

Jawaban:

106

Anda dapat menggunakan os.system(), seperti ini:

import os
os.system('ls')

Atau dalam kasus Anda:

os.system('echo 1 > /proc/sys/net/ipv4/ip_forward')
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080')

Lebih baik lagi, Anda dapat menggunakan panggilan subproses, lebih aman, lebih kuat, dan lebih cepat:

from subprocess import call
call('echo "I like potatos"', shell=True)

Atau, tanpa menggunakan shell:

call(['echo', 'I like potatos'])

Jika Anda ingin menangkap output, salah satu cara melakukannya adalah seperti ini:

import subprocess
cmd = ['echo', 'I like potatos']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

o, e = proc.communicate()

print('Output: ' + o.decode('ascii'))
print('Error: '  + e.decode('ascii'))
print('code: ' + str(proc.returncode))

Saya sangat merekomendasikan pengaturan timeoutdi communicate, dan juga untuk menangkap pengecualian Anda bisa dapatkan ketika menyebutnya. Ini adalah kode yang sangat rawan kesalahan, jadi Anda harus mengharapkan kesalahan terjadi dan menanganinya sesuai.

https://docs.python.org/3/library/subprocess.html

Kira
sumber
23
os.sistem sudah tidak digunakan lagi sejak versi 2.6. Subproses adalah modul yang tepat untuk digunakan.
binarysubstrate
@ biner substrat, usang karena tidak didukung atau tidak tersedia? Saya baru-baru ini mengerjakan mesin dengan 2.7 (bukan karena pilihan), dan os.systemmasih berfungsi.
openwonk
1
Juga, jika menggunakan subprocess.callseperti yang disarankan, Anda mungkin perlu menentukan shell=True... lihat di sini
openwonk
Dengan Python 3.4 shell = True harus dinyatakan sebaliknya perintah panggilan tidak akan berfungsi. Secara default panggilan akan mencoba membuka file yang ditentukan oleh string kecuali shell = True diatur. Ini juga terlihat seperti itu di Python 3.5 panggilan diganti dengan menjalankan
DLH
Kode POSIX generik mungkin harus memanggil decode()dengan charset dari LC_CTYPEvariabel lingkungan.
Mikko Rantalainen
29

Perintah pertama hanya menulis ke file. Anda tidak akan menjalankan itu sebagai perintah shell karena pythondapat membaca dan menulis ke file tanpa bantuan shell:

with open('/proc/sys/net/ipv4/ip_forward', 'w') as f:
    f.write("1")

The iptablesPerintah adalah sesuatu yang Anda mungkin ingin mengeksekusi eksternal. Cara terbaik untuk melakukan ini adalah dengan menggunakan modul subproses .

import subprocess
subprocess.check_call(['iptables', '-t', 'nat', '-A',
                       'PREROUTING', '-p', 'tcp', 
                       '--destination-port', '80',
                       '-j', 'REDIRECT', '--to-port', '8080'])

Perhatikan bahwa metode ini juga tidak menggunakan shell, yang merupakan overhead yang tidak perlu.

jordanm
sumber
13

Cara tercepat:

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

Ini bukan pendekatan yang paling fleksibel; jika Anda memerlukan kontrol lebih besar atas proses Anda daripada "jalankan sekali, sampai selesai, dan blokir sampai keluar", maka Anda harus menggunakan subprocessmodul sebagai gantinya.

Tom Hunt
sumber
8

Sebagai aturan umum, Anda sebaiknya menggunakan python binding kapan pun memungkinkan (menangkap Pengecualian yang lebih baik, di antara kelebihan lainnya.)

Untuk echoperintah, jelas lebih baik menggunakan python untuk menulis dalam file seperti yang disarankan dalam jawaban @ jordanm.

Untuk iptablesperintah, mungkin python-iptables( halaman PyPi , halaman GitHub dengan deskripsi dan dokumen ) akan memberikan apa yang Anda butuhkan (saya tidak memeriksa perintah spesifik Anda).

Ini akan membuat Anda bergantung pada lib eksternal, jadi Anda harus mempertimbangkan manfaatnya. Menggunakan karya subproses, tetapi jika Anda ingin menggunakan output, Anda harus menguraikan sendiri, dan menangani perubahan output dalam iptablesversi yang akan datang .

Jérôme
sumber
Satu hal yang perlu diperhatikan adalah bahwa kode pengujian unit dengan subprocesspanggilan kurang bermanfaat. Ya, Anda dapat mengejek panggilan, tetapi tes harus membuat asumsi tentang hasil pada panggilan eksternal.
jordanm
Jawaban Anda lebih seperti saran. OP secara khusus bertanya bagaimana ia dapat menjalankan perintah sistem linux dari python.
kapad
@ Kapad Ya, tapi dia juga menjelaskan mengapa dia ingin melakukannya dan saya mengusulkan alternatif.
Jérôme
2

Versi python dari shell Anda. Hati-hati, saya belum mengujinya.

from subprocess import run

def bash(command):
        run(command.split())

>>> bash('find / -name null')
/dev/null
/sys/fs/selinux/null
/sys/devices/virtual/mem/null
/sys/class/mem/null
/usr/lib/kbd/consoletrans/null
Timothy Pulliam
sumber
0

Jika Anda ingin menjalankan perintah ini di beberapa sistem lain setelah SSH maka Anda mungkin harus menggunakan modul bernama Paramiko. Ini sangat berguna.

Jika eksekusi perintah harus dilakukan dari mesin lokal maka fungsi modul os akan sangat membantu.

Beranda: https://www.paramiko.org/

Pengembangan: https://github.com/paramiko/paramiko

Mikhilesh Sekhar
sumber