92

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?

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

6 Answers 6

145

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

5
  • 33
    os.system is deprecated since version 2.6. Subprocess is the right module to use. Jan 12, 2016 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, 2018 at 1:04
  • 1
    Also, if using subprocess.call as recommended, you may need to specify shell=True... see here
    – openwonk
    Dec 7, 2018 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, 2019 at 20:19
  • Generic POSIX code should probably call decode() with charset from LC_CTYPE environment variable. Feb 28, 2019 at 19:58
33

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.

14

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.

9

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.

3
  • 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, 2015 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, 2018 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, 2018 at 9:23
3

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
1
  • 1
    String splitting only works for the simple cases. For shell-style command splitting use shlex.split
    – iruvar
    Sep 20, 2020 at 15:00
1

If you want to execute this command in some other system after SSH then you might have to use the module named Paramiko. It is really useful.

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

Homepage: https://www.paramiko.org/

Development: https://github.com/paramiko/paramiko

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .