62

I'm currently studying penetration testing and Python programming. I just want to know how I would go about executing a Linux command in Python. The commands I want to execute are:

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

If I just use print in Python and run it in the terminal will it do the same as executing it as if you was typing it yourself and pressing Enter?

  • 5
    os.system can do this. – fooot Oct 23 '15 at 15:41
  • 2
    and i thought bash was a bloated shell... – mikeserv Oct 23 '15 at 15:44
  • 3
    The docs for os.system recommend using the subprocess module. – jordanm Oct 23 '15 at 15:44
  • Do you need the output of iptables? – Kira Oct 23 '15 at 15:46
  • 2
    This question should be migrated to Stackoverflow. – www139 Nov 8 '17 at 21:39
98

You can use os.system(), like this:

import os
os.system('ls')

Or in your case:

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

Better yet, you can use subprocess's call, it is safer, more powerful and likely faster:

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

Or, without invoking shell:

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

If you want to capture the output, one way of doing it is like this:

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 highly recommend setting a timeout in communicate, and also to capture the exceptions you can get when calling it. This is a very error-prone code, so you should expect errors to happen and handle them accordingly.

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

  • 20
    os.system is deprecated since version 2.6. Subprocess is the right module to use. – binarysubstrate Jan 12 '16 at 17:04
  • @binarysubstrate, deprecated as in not supported or not available? I've been recently working on machine with 2.7 (not by choice), and os.system still works. – openwonk Dec 7 '18 at 1:04
  • 1
    Also, if using subprocess.call as recommended, you may need to specify shell=True... see here – openwonk Dec 7 '18 at 1:12
  • With Python 3.4 the shell=True has to be stated otherwise the call command will not work. By default call will try to open a file specified by the string unless the shell=True is set. It also looks like that in Python 3.5 call is replaced with run – DLH Feb 20 at 20:19
  • Generic POSIX code should probably call decode() with charset from LC_CTYPE environment variable. – Mikko Rantalainen Feb 28 at 19:58
28

The first command simply writes to a file. You wouldn't execute that as a shell command because python can read and write to files without the help of a shell:

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

The iptables command is something you may want to execute externally. The best way to do this is to use the subprocess module.

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

Note that this method also does not use a shell, which is unnecessary overhead.

12

The quickest way:

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

This isn't the most flexible approach; if you need any more control over your process than "run it once, to completion, and block until it exits", then you should use the subprocess module instead.

8

As a general rule, you'd better use python bindings whenever possible (better Exception catching, among other advantages.)

For the echo command, it's obviously better to use python to write in the file as suggested in @jordanm's answer.

For the iptables command, maybe python-iptables (PyPi page, GitHub page with description and doc) would provide what you need (I didn't check your specific command).

This would make you depend on an external lib, so you have to weight the benefits. Using subprocess works, but if you want to use the output, you'll have to parse it yourself, and deal with output changes in future iptables versions.

  • Another thing to note is that unit testing code with subprocess calls is less useful. Yes, you can mock out the calls, but the tests have to make assumptions about the results on the external calls. – jordanm Oct 23 '15 at 17:43
  • Your answer is more like advice. The OP has specifically asked how he can run a linux system command from python. – kapad Apr 5 '18 at 9:03
  • @kapad Yes, but he also specified why he wanted to do so and I proposed an alternative. – Jérôme Apr 5 '18 at 9:23
2

A python version of your shell. Be careful, I haven't tested it.

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
0

But if you want to execute this command in some other system after SSH then you might have to use the module called paramiko .It is really usefull

If the command execution has to be done from local machine then os module functions will be helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.