Esegui comandi shell in Python


65

Attualmente sto studiando i test di penetrazione e la programmazione Python. Voglio solo sapere come farei per eseguire un comando Linux in Python. I comandi che voglio eseguire sono:

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

Se uso solo printin Python e lo eseguo nel terminale, farà lo stesso come eseguirlo come se lo stessi digitando e premendo Enter?


5
os.system può farlo.
fooot,

2
e pensavo bashfosse un guscio gonfio ...
Mikeserv,

3
I documenti per os.systemraccomandare di usare il subprocessmodulo.
Giordania,

Hai bisogno dell'output di iptables?
Kira,

3
Questa domanda dovrebbe essere migrata su StackOverflow.
www139,

Risposte:


106

Puoi usare os.system(), in questo modo:

import os
os.system('ls')

O nel tuo caso:

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')

Meglio ancora, puoi usare la chiamata del sottoprocesso, è più sicura, più potente e probabilmente più veloce:

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

Oppure, senza invocare la shell:

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

Se vuoi catturare l'output, un modo per farlo è come questo:

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))

I altamente consigliabile impostare un timeouta communicate, e anche per catturare le eccezioni che si possono ottenere quando si chiama esso. Questo è un codice molto soggetto a errori, quindi dovresti aspettarti che si verifichino errori e gestirli di conseguenza.

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


23
os.system è obsoleto dalla versione 2.6. Il sottoprocesso è il modulo giusto da usare.
binarysubstrate,

@binarysubstrate, deprecato come in non supportato o non disponibile? Di recente ho lavorato su una macchina con 2.7 (non per scelta), e os.systemfunziona ancora.
openwonk,

1
Inoltre, se si utilizza subprocess.callcome raccomandato, potrebbe essere necessario specificare shell=True... vedere qui
openwonk

Con Python 3.4 è necessario indicare shell = True, altrimenti il ​​comando call non funzionerà. Per impostazione predefinita, la chiamata tenterà di aprire un file specificato dalla stringa a meno che non sia impostata shell = True. Sembra anche che in Python 3.5 la chiamata sia sostituita con run
DLH

Il codice POSIX generico dovrebbe probabilmente chiamare decode()con charset dalla LC_CTYPEvariabile di ambiente.
Mikko Rantalainen,

29

Il primo comando scrive semplicemente in un file. Non lo eseguiresti come comando shell perché pythonpuoi leggere e scrivere su file senza l'aiuto di una shell:

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

Il iptablescomando è qualcosa che potresti voler eseguire esternamente. Il modo migliore per farlo è utilizzare il modulo di sottoprocesso .

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

Si noti che questo metodo inoltre non utilizza una shell, che è un sovraccarico non necessario.


13

Il modo più veloce:

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

Questo non è l'approccio più flessibile; se hai bisogno di più controllo sul tuo processo di "eseguilo una volta, fino al completamento e blocca fino a quando non esce", allora dovresti usare il subprocessmodulo.


8

Come regola generale, è meglio usare i binding di Python ogni volta che è possibile (migliore cattura delle eccezioni, tra gli altri vantaggi).

Per il echocomando, è ovviamente meglio usare python per scrivere nel file come suggerito nella risposta di @ jordanm.

Per il iptablescomando, forse python-iptables( pagina PyPi , pagina GitHub con descrizione e doc ) fornirebbe quello che ti serve (non ho controllato il tuo comando specifico).

Questo ti farebbe dipendere da una lib esterna, quindi devi ponderare i benefici. L'uso del sottoprocesso funziona, ma se si desidera utilizzare l'output, è necessario analizzarlo da soli e gestire le modifiche dell'output nelle iptablesversioni future .


Un'altra cosa da notare è che il codice di unit test con le subprocesschiamate è meno utile. Sì, puoi deridere le chiamate, ma i test devono fare ipotesi sui risultati delle chiamate esterne.
Giordania,

La tua risposta è più simile a un consiglio. L'OP ha specificamente chiesto come può eseguire un comando di sistema Linux da Python.
Kapad,

@kapad Sì, ma ha anche specificato perché voleva farlo e io ho proposto un'alternativa.
Jérôme,

2

Una versione Python della tua shell. Fai attenzione, non l'ho provato.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.