Ejecutar comandos de shell en Python

65

Actualmente estoy estudiando pruebas de penetración y programación de Python. Solo quiero saber cómo haría para ejecutar un comando de Linux en Python. Los comandos que quiero ejecutar son:

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

Si solo lo uso printen Python y lo ejecuto en la terminal, ¿hará lo mismo que ejecutarlo como si lo estuviera escribiendo usted mismo y presionando Enter?

iZodiac
fuente
55
os.system puede hacer esto.
fooot
2
y pensé que bashera una cáscara hinchada ...
mikeserv
3
Los documentos para os.systemrecomendar el uso del subprocessmódulo.
jordanm
¿Necesitas la salida de iptables?
Kira
3
Esta pregunta debe migrarse a Stackoverflow.
www139

Respuestas:

106

Puedes usar os.system(), así:

import os
os.system('ls')

O en tu 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')

Mejor aún, puede usar la llamada del subproceso, es más seguro, más potente y probablemente más rápido:

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

O, sin invocar shell:

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

Si desea capturar la salida, una forma de hacerlo es así:

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

Yo altamente recomiendo el establecimiento de una timeouten communicate, y también para capturar las excepciones que puede obtener cuando se llama a ella. Este es un código muy propenso a errores, por lo que debe esperar que ocurran errores y manejarlos en consecuencia.

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

Kira
fuente
23
os.system está en desuso desde la versión 2.6. El subproceso es el módulo correcto para usar.
binarysubstrate
@binarysubstrate, en desuso como no admitido o no disponible? Recientemente he estado trabajando en la máquina con 2.7 (no por elección), y os.systemtodavía funciona.
openwonk
1
Además, si se utiliza subprocess.callsegún lo recomendado, es posible que tenga que especificar shell=True... ver aquí
openwonk
Con Python 3.4, se debe indicar shell = True; de ​​lo contrario, el comando de llamada no funcionará. Por defecto, call intentará abrir un archivo especificado por la cadena a menos que se establezca shell = True. También parece que en Python 3.5 la llamada se reemplaza con ejecutar
DLH
El código genérico POSIX probablemente debería llamar decode()con el conjunto de caracteres de LC_CTYPEla variable de entorno.
Mikko Rantalainen
29

El primer comando simplemente escribe en un archivo. No ejecutarías eso como un comando de shell porque pythonpuedes leer y escribir en archivos sin la ayuda de un shell:

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

El iptablescomando es algo que puede querer ejecutar externamente. La mejor manera de hacerlo es usar el módulo de subproceso .

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

Tenga en cuenta que este método tampoco utiliza un shell, que es una sobrecarga innecesaria.

jordanm
fuente
13

La forma más rápida:

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

Este no es el enfoque más flexible; si necesita más control sobre su proceso que "ejecutarlo una vez, hasta completarlo y bloquear hasta que salga", entonces debe usar el subprocessmódulo en su lugar.

Tom Hunt
fuente
8

Como regla general, será mejor que use enlaces de python siempre que sea posible (mejor captura de excepciones, entre otras ventajas).

Para el echocomando, obviamente es mejor usar python para escribir en el archivo como se sugiere en la respuesta de @ jordanm.

Para el iptablescomando, tal vez python-iptables( página PyPi , página GitHub con descripción y documento ) proporcionaría lo que necesita (no verifiqué su comando específico).

Esto te haría depender de una biblioteca externa, por lo que debes sopesar los beneficios. El uso de subprocesos funciona, pero si desea usar la salida, tendrá que analizarlo usted mismo y manejar los cambios de salida en futuras iptablesversiones.

Jérôme
fuente
Otra cosa a tener en cuenta es que el código de prueba de la unidad con subprocessllamadas es menos útil. Sí, puede burlarse de las llamadas, pero las pruebas tienen que hacer suposiciones sobre los resultados de las llamadas externas.
jordanm
Tu respuesta es más como un consejo. El OP ha preguntado específicamente cómo puede ejecutar un comando del sistema Linux desde python.
kapad
@kapad Sí, pero también especificó por qué quería hacerlo y propuse una alternativa.
Jérôme
2

Una versión en python de tu shell. Ten cuidado, no lo he probado.

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
fuente
0

Si desea ejecutar este comando en otro sistema después de SSH, entonces puede que tenga que usar el módulo llamado Paramiko. Es realmente útil

Si la ejecución del comando tiene que hacerse desde la máquina local, entonces las funciones del módulo os serán útiles.

Página de inicio: https://www.paramiko.org/

Desarrollo: https://github.com/paramiko/paramiko

Mikhilesh Sekhar
fuente