Executar comandos do shell em Python

65

Atualmente, estou estudando testes de penetração e programação Python. Eu só quero saber como eu iria executar um comando Linux em Python. Os comandos que eu quero executar são:

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

Se eu apenas usar printem Python e executá-lo no terminal, ele fará o mesmo que executá-lo, como se você estivesse digitando e pressionando Enter?

iZodiac
fonte
5
o os.system pode fazer isso.
Fooot
2
e eu pensei que bashera uma concha inchado ...
mikeserv
3
Os documentos para os.systemrecomendar o uso do subprocessmódulo.
Jordanm # 23/15
Você precisa da saída do iptables?
Kira
3
Esta pergunta deve ser migrada para o Stackoverflow.
www139 8/11

Respostas:

106

Você pode usar os.system(), assim:

import os
os.system('ls')

Ou no seu 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')

Melhor ainda, você pode usar a chamada do subprocesso, é mais segura, mais poderosa e provavelmente mais rápida:

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

Ou, sem chamar o shell:

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

Se você deseja capturar a saída, uma maneira de fazer isso é assim:

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 recomendável definir uma timeoutem communicate, e também para capturar as exceções que você pode começar quando chamá-lo. Este é um código muito propenso a erros, portanto, espere que ocorram erros e os manipule adequadamente.

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

Kira
fonte
23
o os.system está obsoleto desde a versão 2.6. Subprocesso é o módulo certo para usar.
precisa saber é o seguinte
@binarysubstrate, descontinuado como não é suportado ou não está disponível? Eu estive trabalhando recentemente na máquina com 2.7 (não por opção) e os.systemainda funciona.
Openwonk 07/12
11
Além disso, se usar subprocess.callcomo recomendado, você pode precisar especificar shell=True... veja aqui
openwonk
No Python 3.4, o shell = True deve ser declarado, caso contrário, o comando call não funcionará. Por padrão, a chamada tentará abrir um arquivo especificado pela sequência, a menos que o shell = True esteja definido. Também parece que no Python 3.5 a chamada é substituída pela execução
DLH
O código POSIX genérico provavelmente deve chamar decode()com charset da LC_CTYPEvariável de ambiente.
Mikko Rantalainen 28/02
29

O primeiro comando simplesmente grava em um arquivo. Você não executaria isso como um comando do shell, porque pythonpode ler e gravar em arquivos sem a ajuda de um shell:

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

O iptablescomando é algo que você pode querer executar externamente. A melhor maneira de fazer isso é usar o módulo de subprocesso .

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

Observe que esse método também não usa um shell, o que é uma sobrecarga desnecessária.

jordanm
fonte
13

A maneira mais rápida:

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

Essa não é a abordagem mais flexível; se você precisar de mais controle sobre seu processo do que "execute-o uma vez até a conclusão e bloqueie até que ele saia", use o subprocessmódulo.

Tom Hunt
fonte
8

Como regra geral, é melhor usar as ligações python sempre que possível (captura melhor de exceções, entre outras vantagens).

Para o echocomando, é obviamente melhor usar python para escrever no arquivo, conforme sugerido na resposta do @ jordanm.

Para o iptablescomando, talvez python-iptables( página PyPi , página GitHub com descrição e doc ) forneça o que você precisa (não verifiquei seu comando específico).

Isso faria você depender de uma lib externa, então você deve ponderar os benefícios. O uso do subprocesso funciona, mas se você quiser usar a saída, será necessário analisá-la e lidar com as alterações na saída em iptablesversões futuras .

Jérôme
fonte
Outro aspecto a ser observado é que o código de teste de unidade com subprocesschamadas é menos útil. Sim, você pode simular as chamadas, mas os testes precisam fazer suposições sobre os resultados nas chamadas externas.
Jordanm # 23/15
Sua resposta é mais como um conselho. O OP perguntou especificamente como ele pode executar um comando do sistema linux a partir do python.
kapad
@ Kapap Sim, mas ele também especificou por que queria fazê-lo e propus uma alternativa.
Jérôme
2

Uma versão python do seu shell. Cuidado, eu não testei.

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

Se você deseja executar este comando em algum outro sistema após o SSH, pode ser necessário usar o módulo chamado Paramiko. Isso é realmente útil.

Se a execução do comando precisar ser realizada na máquina local, as funções do módulo OS serão úteis.

Página inicial: https://www.paramiko.org/

Desenvolvimento: https://github.com/paramiko/paramiko

Mikhilesh Sekhar
fonte