Exécuter des commandes shell en Python

65

J'étudie actuellement les tests d' intrusion et la programmation Python. Je veux juste savoir comment j'exécuterais une commande Linux en Python. Les commandes que je veux exécuter sont:

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

Si je l’utilise seulement printen Python et que je l’exécute dans le terminal, est-ce que cela fonctionnera de la même manière que si on le tapait soi-même et que l’on appuyait Enter?

iZodiac
la source
5
os.system peut le faire.
Fooot
2
et je pensais bashêtre une coquille gonflée ...
mikeserv
3
Les docs pour os.systemrecommander l'utilisation du subprocessmodule.
Jordanie
Avez-vous besoin de la sortie d'iptables?
Kira
3
Cette question devrait être migrée vers Stackoverflow.
www139

Réponses:

106

Vous pouvez utiliser os.system()comme ceci:

import os
os.system('ls')

Ou dans votre cas:

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

Mieux encore, vous pouvez utiliser l'appel du sous-processus, il est plus sûr, plus puissant et probablement plus rapide:

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

Ou, sans invoquer shell:

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

Si vous voulez capturer la sortie, une façon de le faire est la suivante:

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

Je fortement recommande la fixation d' un timeouten communicateet aussi de capturer les exceptions que vous pouvez obtenir lors de l' appel. C'est un code très sujet aux erreurs, vous devez donc vous attendre à ce que des erreurs se produisent et les gérer en conséquence.

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

Kira
la source
23
os.system est obsolète depuis la version 2.6. Le sous-processus est le bon module à utiliser.
binarysubstrate
@binarysubstrate, obsolète comme non supporté ou non disponible? Je travaille depuis peu sur la machine avec la version 2.7 (et non par choix), et os.systemfonctionne toujours.
openwonk
1
Aussi, si vous utilisez subprocess.callcomme recommandé, vous devrez peut-être spécifier shell=True... voir ici
openwonk
Avec Python 3.4, le shell = True doit être indiqué, sinon la commande call ne fonctionnera pas. Par défaut, call tentera d'ouvrir un fichier spécifié par la chaîne sauf si le shell = True est défini. Il semble aussi que dans Python 3.5, l'appel soit remplacé par run
DLH
Le code POSIX générique devrait probablement appeler decode()avec charset à partir d' LC_CTYPEune variable d'environnement.
Mikko Rantalainen le
29

La première commande écrit simplement dans un fichier. Vous n'exécuteriez pas cela en tant que commande shell car vous pythonpouvez lire et écrire dans des fichiers sans l'aide d'un shell:

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

La iptablescommande est quelque chose que vous pouvez exécuter en externe. La meilleure façon de procéder consiste à utiliser le module de sous - processus .

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

Notez que cette méthode n’utilise pas non plus de shell, ce qui est une surcharge inutile.

Jordan
la source
13

Le moyen le plus rapide:

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

Ce n'est pas l'approche la plus flexible; si vous avez besoin de plus de contrôle sur votre processus que "l'exécuter une fois, jusqu'à son achèvement, et le bloquer jusqu'à ce qu'il se ferme", vous devez alors utiliser le subprocessmodule.

Tom Hunt
la source
8

En règle générale, vous feriez mieux d'utiliser des liaisons python chaque fois que possible (meilleure capture des exceptions, parmi d'autres avantages.)

Pour la echocommande, il est évidemment préférable d’utiliser python pour écrire dans le fichier comme suggéré dans la réponse de @ jordanm.

Pour la iptablescommande, peut - être python-iptables( la page PyPI , la page GitHub avec description et doc ) fournirait ce dont vous avez besoin (je n'ai pas vérifié votre commande spécifique).

Cela vous obligerait à utiliser une bibliothèque externe, de sorte que vous devez pondérer les avantages. L'utilisation de sous-processus fonctionne, mais si vous souhaitez utiliser la sortie, vous devrez l'analyser vous-même et gérer les modifications de sortie dans les iptablesversions futures .

Jérôme
la source
Une autre chose à noter est que le code de test unitaire avec subprocessappels est moins utile. Oui, vous pouvez simuler les appels, mais les tests doivent émettre des hypothèses sur les résultats des appels externes.
Jordanie
Votre réponse ressemble plus à un conseil. L'OP a spécifiquement demandé comment il peut exécuter une commande système linux à partir de python.
kapad
@ kapad Oui, mais il a également précisé pourquoi il voulait le faire et j'ai proposé une alternative.
Jérôme
2

Une version python de votre shell. Attention, je ne l'ai pas testé.

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
la source
0

Si vous souhaitez exécuter cette commande sur un autre système après SSH, vous devrez peut-être utiliser le module nommé Paramiko. C'est vraiment utile.

Si l'exécution de la commande doit être effectuée à partir de la machine locale, les fonctions du module os seront utiles.

Page d'accueil: https://www.paramiko.org/

Développement: https://github.com/paramiko/paramiko

Mikhilesh Sekhar
la source