I am trying to call the following command in my python script. I am trying to insert the rule into IP tables. I am using sub process to call it and inserting variables into it where needed, but am getting a large error. Any suggestions?
iptables = subprocess.call('iptables -I FORWARD -eth 0 -m '+protocol+' -t'+protocol+'--dport '+port+'-j DNAT --to-destination'+ipAddress)
Error:
Traceback (most recent call last):
File "./port_forward.py", line 42, in <module>
iptables = subprocess.call('iptables -I FORWARD -i eth0 -m '+protocol+' -t'+protocol+'--dport '+port+'-j DNAT --to-destination'+ipAddress)
File "/usr/lib/python2.7/subprocess.py", line 493, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1259, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Your problem is very common for Python beginners. Instead of formatting the string command,
you are trying to build a complex string by concatenating many strings and variables. Instead, use a
a string format, it will allow you to test your command and make your code more readable and flexible.
Your original string lacks spaces between the options and the arguments, e.g. --to-destination1.2.3.4.
Hence, you should format your string (This works also for python 2.7):
opts = {'iptables': '/sbin/iptables', 'protocol': 'tcp', 'port': 80, 'ipAddress': '0.0.0.0'}
ipcmd = '{iptables} -I FORWARD -eth 0 -m {protocol} -t {protocol} \
--dport {port} -j DNAT --to-destination {ipAddress}'.format(**opts)
if DEBUG:
print ipcmd
iptables = subprocess.call(ipcmd)
This is much easier to modify later, and also, when you do more Python programming, you will see that it is more readable.
Also, to call IPTables, you should be root, as stated in the comments:
In the beginning of your script add:
import sys
import os
if not os.getuid() == 0:
print "You must be root to change IPTables."
sys.exit(2)
update after seeing your error trace:
You are trying to call a command iptables but it is not in your path.
You should call the full path of iptables , e.g. /sbin/iptables
I wrote a simple firewall the same way and realized, "why not just write it in bash?". Anyway I discovered the python-iptables library and rewrote my code using that. I recommend checking it out. I think it will give you a more robust and structured way of writing iptables rules.
Your command is full of syntax errors due to missing spaces, as shown below:
iptables = subprocess.call(
'iptables -I FORWARD -eth 0 -m '
+ protocol
+ ' -t'+protocol
^---here
+ '--dport '
^-- here
+ port
+ '-j DNAT --to-destination'
^--here
+ ipAddress)
^---here
As generated, your iptables line will look like
-ttcp--dport 80-j DNAT --to-destination1.2.3.4
-ttcp--dport is parsed as a SINGLE argument, ditto for 80-j and --to-destination1.2.3.4
Just pass the argument shell=True along with the command.
iptables = subprocess.call('iptables -I FORWARD -eth 0 -m '+protocol+' -t'+protocol+'--dport '+port+'-j DNAT --to-destination'+ipAddress, shell=True)
Related
I tried to add watermark to a video using python by call subprocess ffmpeg. My code:
command = "C:\\VidMaker\\source\\ffmpeg.win32.exe -i C:\\VidMaker\\kq"+str(i)+".mp4 -i C:\\VidMaker\\1.png -filter_complex" "[0:v]setsar=sar=1[v];[v][1]blend=all_mode='overlay':all_opacity=0.7" "-vcodec libx264 C:\VidMaker\\Res"+str(i)+".mp4"
subprocess.check_call(command, shell = False)
the result is:
Unrecognized option 'filter_complex[0:v]setsar=sar=1[v];[v][1]blend=all_mode='overlay':all_opacity=0.7-movflags'.
Error splitting the argument list: Option not found
Traceback (most recent call last):
File "C:\VidMaker\add.py", line 10, in <module>
subprocess.check_call(command, shell = False)
File "C:\Python27\lib\subprocess.py", line 186, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'C:\VidMaker\source\ffmpeg.win32.exe -n -i C:\VidMaker\kq2.mp4 -i C:\VidMaker\1.png -filter_complex[0:v]setsar=sar=1[v];[v][1]blend=all_mode='overlay':all_opacity=0.7-movflags +faststart C:\VidMaker\Res2.mp4' returned non-zero exit status 1
[Finished in 0.4s with exit code 1]
edit1: it run ok without option:
command = "C:\\VidMaker\\source\\ffmpeg.win32.exe -i C:\\VidMaker\\kq"+str(i)+".mp4 -i C:\\VidMaker\\1.png -filter_complex overlay=10:10 C:\VidMaker\\Res"+str(i)+".mp4"
What happen with the option and how can fix it?Thanks!
edit2: i need to call like that because my VPS cannot run like my computer, in my computer it run successfully with:
subprocess.call(['ffmpeg',
'-i', 'funvi 155.mp4',
'-i', '1.png',
'-filter_complex', "[1:v]format=argb,geq=r='r(X,Y)':a='0.15*alpha(X,Y)'[zork]; [0:v][zork]overlay",
'-vcodec', 'libx264',
'myresult6.mp4'])
It is concatenating your string literals:
"A" "B"
Becomes "AB", not "A B", no space is added. So either use one single quoted string with spaces between your command line parameters, or find another way to store command line parameters, e.g. in a list, then you can pass that list to subprocess or whatever later when you're ready to run it.
Sorry to be brief, on phone.
I am having hard time parsing the arguments to subprocess.Popen. I am trying to execute a script on my Unix server. The script syntax when running on shell prompt is as follows:
/usr/local/bin/script hostname = <hostname> -p LONGLIST. No matter how I try, the script is not running inside subprocess.Popen
The space before and after "=" is mandatory.
import subprocess
Out = subprocess.Popen(['/usr/local/bin/script', 'hostname = ', 'actual server name', '-p', 'LONGLIST'],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
The above does not work.
And when I use shell=False, I get OSError: [Errno 8] Exec format error
OSError: [Errno 8] Exec format error can happen if there is no shebang line at the top of the shell script and you are trying to execute the script directly. Here's an example that reproduces the issue:
>>> with open('a','w') as f: f.write('exit 0') # create the script
...
>>> import os
>>> os.chmod('a', 0b111101101) # rwxr-xr-x make it executable
>>> os.execl('./a', './a') # execute it
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/os.py", line 312, in execl
execv(file, args)
OSError: [Errno 8] Exec format error
To fix it, just add the shebang e.g., if it is a shell script; prepend #!/bin/sh at the top of your script:
>>> with open('a','w') as f: f.write('#!/bin/sh\nexit 0')
...
>>> os.execl('./a', './a')
It executes exit 0 without any errors.
On POSIX systems, shell parses the command line i.e., your script won't see spaces around = e.g., if script is:
#!/usr/bin/env python
import sys
print(sys.argv)
then running it in the shell:
$ /usr/local/bin/script hostname = '<hostname>' -p LONGLIST
produces:
['/usr/local/bin/script', 'hostname', '=', '<hostname>', '-p', 'LONGLIST']
Note: no spaces around '='. I've added quotes around <hostname> to escape the redirection metacharacters <>.
To emulate the shell command in Python, run:
from subprocess import check_call
cmd = ['/usr/local/bin/script', 'hostname', '=', '<hostname>', '-p', 'LONGLIST']
check_call(cmd)
Note: no shell=True. And you don't need to escape <> because no shell is run.
"Exec format error" might indicate that your script has invalid format, run:
$ file /usr/local/bin/script
to find out what it is. Compare the architecture with the output of:
$ uname -m
I will hijack this thread to point out that this error may also happen when target of Popen is not executable. Learnt it hard way when by accident I have had override a perfectly executable binary file with zip file.
Have you tried this?
Out = subprocess.Popen('/usr/local/bin/script hostname = actual_server_name -p LONGLIST'.split(), shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
Edited per the apt comment from #J.F.Sebastian
It wouldn't be wrong to mention that Pexpect does throw a similar error
#python -c "import pexpect; p=pexpect.spawn('/usr/local/ssl/bin/openssl_1.1.0f version'); p.interact()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python2.7/site-packages/pexpect.py", line 430, in __init__
self._spawn (command, args)
File "/usr/lib/python2.7/site-packages/pexpect.py", line 560, in _spawn
os.execv(self.command, self.args)
OSError: [Errno 8] Exec format error
Over here, the openssl_1.1.0f file at the specified path has exec command specified in it and is running the actual openssl binary when called.
Usually, I wouldn't mention this unless I have the root cause, but this problem was not there earlier. Unable to find the similar problem, the closest explanation to make it work is the same as the one provided by #jfs above.
what worked for me is both
adding /bin/bash at the beginning of the command or file you are
facing the problem with, or
adding shebang #!/bin/sh as the first line.
for ex.
#python -c "import pexpect; p=pexpect.spawn('/bin/bash /usr/local/ssl/bin/openssl_1.1.0f version'); p.interact()"
OpenSSL 1.1.0f 25 May 2017
If you think the space before and after "=" is mandatory, try it as separate item in the list.
Out = subprocess.Popen(['/usr/local/bin/script', 'hostname', '=', 'actual server name', '-p', 'LONGLIST'],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
I have to connect to a sybase database and run a simple select query using python script
On my server isql command can run only from sybase bin directory, so i have to cd to that directory before firing the query.
---------------------------Edited-----------------------------
Uptill now i'm able to do this:-
#!/usr/bin/python
import subprocess
path = "path/to/sybase/bin"
os.chdir(path)
arguments = ['./isql',"-S server_name", "-U user", "-P password", "-D database","""<<EOF
SELECT * FROM sometable
go
EOF"""]
ps = subprocess.Popen(arguments)
out = ps.communicate()
print out
The errors are just out of my understanding capability :(
Traceback (most recent call last):
File "./test_db.py", line 8, in ?
ps = subprocess.Popen(arguments)
File "/usr/lib64/python2.4/subprocess.py", line 542, in __init__
errread, errwrite)
File "/usr/lib64/python2.4/subprocess.py", line 975, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
I'm able to do this outside my python script using isql command on my unix terminal
how can i use isql in python subprocess module?
There is a particular Popen argument for that: cwd, as mentioned here. Provide your command using an array and then the cwd parameter with where the command must be executed:
subprocess.Popen(['ls', '-l'], cwd="/path/to/folder")
Popen only takes one args argument, for the command to run. You could try calling a shell with both the cd and isql commands as arguments, but changing the working directory from python is probably simpler
For the former approach:
subprocess.Popen('/bin/sh -c "cd /path/to/... && isql -arg1..'...)
for the latter:
os.chdir('/path/to...')
subprocess.Popen('isql -arg1..'...)
Try:
import os
import subprocess
os.chdir('/path/to/sybase/bin')
if os.path.exists('isql') or os.path.exists(os.path.join('/path/to/sybase/bin', 'isql')):
ps = subprocess.Popen('isql -S %s -U %s -P %s -D %s <<EOF SELECT * FROM sometable EOF' % (server,user,passwd,database), stdout=subprocess.PIPE, shell=True)
out, err = ps.communicate()
else:
print "isql does not exists in this folder"
I am not super experienced with subprocess but this is how I generally use it on the odd occasion. Hopefully someone else can give a better answer/explanation.
Edit: removed the square brackets to remove confusion.
i know it's been long but just wanted to close this question
from subprocess import Popen, PIPE
from textwrap import dedent
isql = Popen(['./isql', '-I', '/app/sybase/...',
'-S', mdbserver,
'-U', muserid,
'-P', password, ...,
'-w', '99999'], stdin=PIPE, stdout=PIPE, cwd=sybase_path)
output = isql.communicate(dedent("""\
SET NOCOUNT ON
{}
go
""".format(User_Query)))[0]
This question already has answers here:
Why does passing variables to subprocess.Popen not work despite passing a list of arguments?
(5 answers)
Closed 1 year ago.
1 import subprocess
2 raw = raw_input("Filename:").lower()
3 ip = raw_input("Host:").lower()
4 cmd = subprocess.call("tcpdump -c5 -vvv -w" + " raw " + " ip ",shell=True)
So this is my script. I everything works besides one key objective, using the raw input.
It allows me to input anything i want, but when it goes to saving the file or using an ip/host doe doesn't actually do anything.
Sure it gives me the packets, but from the localhost not the host i type in.
how i know this isn't working is cause my first raw input is the filename, so i put in test, when i look in the folder were my script is, it produces a file called "raw" meaning, its not actually taking my input only using whats inside my "X"...
So i make a few chances to come to this:
1 import subprocess
2 raw = raw_input("Filename:").lower()
3 ip = raw_input("Host:").lower()
4 cmd = subprocess.call("tcpdump -c5 -vvv -w" + raw + "host" + ip,shell=True)
Which is great because it actually calls for the -w but it saves it now as rawhostip instead of "raw"s input.
for reference this is what the command looks like in the terminal:
tcpdump -c5 -vvv -w savename host wiki2
the only two variabls are savename and wiki2 the rest are needed for the command to work.
with this script i get this error:
import subprocess
raw = raw_input("Filename:").lower()
ip = raw_input("Host:").lower()
cmd = subprocess.call("tcpdump -c5 -vvv -w" + raw, "host" + ip,shell=True)
Error:
Traceback (most recent call last):
File "te.py", line 4, in <module>
cmd = subprocess.call("tcpdump -c5 -vvv -w" + raw, "host" + ip,shell=True)
File "/usr/lib/python2.6/subprocess.py", line 480, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.6/subprocess.py", line 583, in __init__
raise TypeError("bufsize must be an integer")
TypeError: bufsize must be an integer
I am at a lost. Any help will be great, yes I know look at subprocess's doc's on site:X, I have I need a human to teach me, I don't understand what I am reading.
My question is how do I work with these variables.
Don't use shell=True. That should be False.
You are making subtle mistakes with the input. Specifically, if you have two strings:
>>> s1 = 'Hello'
>>> s2 = 'Hi'
>>> s1 + s2
'HelloHi'
Notice, there is no space between Hello and Hi. So don't do this. (Your line 4)
You should do (the good way):
>>> raw = raw_input('Filename: ')
Filename: test
>>> ip = raw_input('Host: ')
Host: 192.168.1.1
>>> command = 'tcpdump -c5 -vvv -w {0} {1}'.format(raw, ip) # the command goes here
>>> subprocess.call(command.split(), shell=False) # call subprocess and pass the command as a list using split
Now it should work.
You should not use the string form ob the subprocess functions. Try:
subprocess.check_call(["tcpdump", "-c5", "-vvv", "-w", raw, "host", ip])
I'm setting up a program to connect my computer to our schools proxy and currently have something like this:
import subprocess
import sys
username = 'fergus.barker'
password = '*************'
proxy = 'proxy.det.nsw.edu.au:8080'
options = '%s:%s#%s' % (username, password, proxy)
subprocess.Popen('export http_proxy=' + options)
But upon running I get:
Traceback (most recent call last):
File "school_proxy_settings.py", line 19, in <module>
subprocess.Popen('export http_proxy=' + options)
File "/usr/lib/python2.6/subprocess.py", line 621, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1126, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Why is this happening please guys?
The problem is that export is not an actual command or file. It is a built-in command to shells like bash and sh, so when you attempt a subprocess.Popen you will get an exception because it can not find the export command. By default Popen does an os.execvp() to spawn a new process, which would not allow you to use shell intrinsics.
You can do something like this, though you have to change your call to Popen.
http://docs.python.org/library/subprocess.html
You can specify shell=True to make it use shell commands.
class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
On Unix, with shell=True: If args is a string, it specifies the command string to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself. That is to say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
export is not a separate binary on your system, it is actually just a command within the shell itself. For example, try using which rm on your system. You'll probably see something like:
[21:16:28] ~ $ which rm
/bin/rm
Now try using which export. You'll get something like:
[21:16:37] ~ $ which export
/usr/bin/which: no export in (/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:
/usr/kerberos/bin:/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin:
/usr/local/sbin:/usr/sbin:/sbin:/home/carter/bin)
So you can't actually invoke an export process/subprocess by default. You may want to look at os.putenv() and os.environ() instead.