I am having a difficult time understanding how to get python to call a system command with the subprocess.Popen function.
the_file = ('logs/consolidated.log.gz')
webstuff = subprocess.Popen(['/usr/bin/zgrep', '/meatsauce/', the_file ],stdout=subprocess.PIPE)
for line in webstuff.stdout:
print line
Trying to get python to build another file with my search string.
The problem is in how you're constructing your arguments. The way you have it now, you're running:
/usr/bin/zgrep /meatsauce/ logs/consolidated.log.gz
Note the space between /meatsauce/ and logs...
To do what I think you're intending, use os.path.join a la:
import os
the_file = 'logs/consolidated.log.gz'
webstuff = subprocess.Popen(['/usr/bin/zgrep', os.path.join('/meatsauce/', the_file)],stdout=subprocess.PIPE) % dpt_search
for line in webstuff.stdout:
print line
Not exactly sure about your question, but the following snippet will call zgrep with two arguments, a searchterm and a filename - and print the result (stdout) line by line:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
# filename and searchterm
fn, term = 'access_log.gz', 'hello'
p = subprocess.Popen(['/usr/bin/zgrep', term, fn], stdout=subprocess.PIPE)
for line in p.stdout:
print line
In the code you posted the string interpolation (% dpt_search) does not work out, since there is not pure string in front of the modulo sign - in fact it should fail with something like:
TypeError: "unsupported operand type(s) for %: 'Popen' and 'str'"
the_file = ('webalizerlogs/consolidated.log.gz')
output_f = open('output.txt','w')
webstuff = subprocess.Popen(['/usr/bin/zgrep', dpt_search, the_file ],stdout=output_f)
I think you are simply trying to grep the a content in the a file. Is it?
import os
import subprocess
the_file = os.path.join(os.getcwd(),'logs/consolidated.log.gz')
proc = subprocess.Popen(['/usr/bin/zgrep', dpt_search, the_file], stdout=subprocess.PIPE)
out, err = proc.communicate()
with open('resultoutput','w') as f:
f.write(out)
subprocess.call(['/usr/bin/zip',os.path.join(os.getcwd(),'resultoutput'])
Check the docs as well.
Related
I have a python code in which I am calling a shell command. The part of the code where I did the shell command is:
try:
def parse(text_list):
text = '\n'.join(text_list)
cwd = os.getcwd()
os.chdir("/var/www/html/alenza/hdfs/user/alenza/sree_account/sree_project/src/core/data_analysis/syntaxnet/models/syntaxnet")
synnet_output = subprocess.check_output(["echo '%s' | syntaxnet/demo.sh 2>/dev/null"%text], shell = True)
os.chdir(cwd)
return synnet_output
except Exception as e:
sys.stdout.write(str(e))
Now, when i run this code on a local file with some sample input (I did cat /home/sree/example.json | python parse.py) it works fine and I get the required output. But I am trying to run the code with an input on my HDFS (the same cat command but input file path is from HDFS) which contains exactly the same type of json entries and it fails with an error:
/bin/sh: line 62: to: command not found
list index out of range
I read similar questions on Stack Overflow and the solution was to include a Shebang line for the shell script that is being called. I do have the shebang line #!/usr/bin/bash in demo.sh script.
Also, which bash gives /usr/bin/bash.
Someone please elaborate.
You rarely, if ever, want to combine passing a list argument with shell=True. Just pass the string:
synnet_output = subprocess.check_output("echo '%s' | syntaxnet/demo.sh 2>/dev/null"%(text,), shell=True)
However, you don't really need a shell pipeline here.
from subprocess import check_output
from StringIO import StringIO # from io import StringIO in Python 3
synnet_output = check_output(["syntaxnet/demo.sh"],
stdin=StringIO(text),
stderr=os.devnull)
There was a problem with some special characters appearing in the text string that i was inputting to demo.sh. I solved this by storing text into a temporary file and sending the contents of that file to demo.sh.
That is:
try:
def parse(text_list):
text = '\n'.join(text_list)
cwd = os.getcwd()
with open('/tmp/data', 'w') as f:
f.write(text)
os.chdir("/var/www/html/alenza/hdfs/user/alenza/sree_account/sree_project/src/core/data_analysis/syntaxnet/models/syntaxnet")
synnet_output = subprocess.check_output(["cat /tmp/data | syntaxnet/demo.sh 2>/dev/null"%text], shell = True)
os.chdir(cwd)
return synnet_output
except Exception as e:
sys.stdout.write(str(e))
I'm trying to write a simple script that takes a list of words I've created in a text file on linux and runs it through a program that checks the word against a steganography extractor.
The program (steghide) uses the following syntax in the command:
steghide --extract -p {password here} -sf {filename here}
I've been able to call the file and set up a for loop for the words in the list, but can not find a way to input the word from that iteration into each command.
Here's how I've been trying to work it.
import os
import sys
script, filename = argv
filename2 = sys.open(filename)
for word in filename2:
os.system('steghide --extract -p [want to put something here] -sf stegfilename')
I'm on a controlled box and can't download anything beyond what I already have. Any help is appreciated.
Update:
I got it to work. But now I'm trying to get it to exit out if it finds the correct answer. I am just having a hard time getting Python to read the output. Here's what I have so far.
`import subprocess
from sys import argv
script, filename = argv
passes = filename
with open(passes) as f:
for line in f:
proc = subprocess.popen(['steghide', '--extract', '-p' line.strip(), '-sf', 'stegged file name'],stdout = subprocess.PIPE)
stdout = proc.communicate()[0]
output = proc.stdout.readline()
if 'wrote' in output:
print 'YOU FOUND IT!'
break
else:
print line`
This is a good time to learn string formating options in Python. They let you insert values dynamically into a string. An example:
"This {0} is an example".format([1,2,3])
>>>> "This [1,2,3] is an example"
In this particular case, you want to do
value = 'foo' # the item you want to insert - replace with list, number, etc.
...
for word in filename2:
os.system('steghide --extract -p {0} -sf stegfilename'.format(value))
This will insert the value into your string, and then call steghide on that string.
Use the subprocess module instead; it gives you more options/control and os.system() is deprecated.
import subproces
with open(filename, "r") as f:
# assumes that you have one word per line
for line in f:
subprocess.call(['steghide', '--extract', '-p', line.strip(), '-sf', stegfilename])
# or if you want the output of running Niels Provos' cool, old tool :)
cmd_output = subprocess.check_output(['steghide', '--extract', '-p', line.strip(), '-sf', stegfilename])
Use subprocess.check_call passing a list of args:
from subprocess import check_call
for word in map(str.rstrip, filename2):
check_call(['steghide', "--extract", "-p", word, "-sf", "stegfilename'"])
String formatting is the subject here.
import os
import sys
script, filename = argv
filename2 = sys.open(filename)
for word in filename2:
os.system('steghide --extract -p ' +[want to put something here]+ '-sf stegfilename')
To join all elements of a list in a string, try python join:
' '.join(your_variable)
Example:
var = ['t', 't', 't', 't', 't', 't']
joined = ' '.join(var)
print(joined)
print(type(joined))
t t t t t t
class 'str'
I am writing something for static analysis of source code in different languages. As anything has to be open source and callable from command line I now have downloaded one tool per language. So I decided to write a python script listing all source files in a project folder and calling the respective tool.
So part of my code looks like this:
import os
import sys
import subprocess
from subprocess import call
from pylint.lint import Run as pylint
class Analyser:
def __init__(self, source=os.getcwd(), logfilename=None):
# doing initialization stuff
self.logfilename = logfilename or 'CodeAnalysisReport.log'
self.listFiles()
self.analyseFiles()
def listFiles(self):
# lists all source files in the specified directory
def analyseFiles(self):
self.analysePythons()
self.analyseCpps()
self.analyseJss()
self.analyseJavas()
self.analyseCs()
if __name__ == '__main__':
Analyser()
Let's have at a look at the C++ files part (I use Cppcheck to analyse those):
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
call(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile])
The console output for one of the files (it's just a random downloaded file) is:
**********************************************************************
C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc
Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc...
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:18]: (style) The scope of the variable 'oldi' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:43]: (style) The scope of the variable 'lastbit' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:44]: (style) The scope of the variable 'two_to_power_i' can be reduced.
(information) Cppcheck cannot find all the include files (use --check-config for details)
Line 1 and 2 coming from my script, lines 3 to 7 coming from Cppcheck.
And this is what I want to save to my log file, for all the other files too. Everything in one single file.
Of course I have searched SO and found some methods. But none is working completely.
First try:
Adding sys.stdout = open(self.logfilename, 'w') to my constructor. This makes line 1 and 2 of the above showed output be written to my log file. The rest is still shown on console.
Second try:
Additionaly, in analyseCpps I use:
call(['C:\CodeAnalysis\cppcheck\cppcheck', '--enable=all', sourcefile], stdout=sys.stdout)
This makes my log file to be:
Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc...
**********************************************************************
C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc
and the console output is:
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:18]: (style) The scope of the variable 'oldi' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:43]: (style) The scope of the variable 'lastbit' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:44]: (style) The scope of the variable 'two_to_power_i' can be reduced.
Not what I want.
Third try:
Using Popen with pipe. sys.stdout is back to default.
As preliminary work analyseCpps now is:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stdout=subprocess.PIPE)
p.stdout.read()
p.stdout.read() shows only the last line of my desired output (line 7 in code box 3)
Fourth try:
Using subprocess.Popen(['C:\CodeAnalysis\cppcheck\cppcheck', '--enable=all', sourcefile], stdout=open(self.logfilename, 'a+')) just writes the one line Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc... to my logfile, the rest is shown on the console.
Fifth try:
Instead of subprocess.Popen I use os.system, so my calling command is:
os.system('C:\CodeAnalysis\cppcheck\cppcheck --enable=all %s >> %s' % (sourcefile, self.logfilename))
This results in the same log file as my fourth try. If I type the same command directly in the windows console the result is the same. So I guess it it is not exactly a python problem but still:
If it is on the console there must be a way to put it in a file. Any ideas?
E D I T
Foolish me. I'm still a noob so I forgot about the stderr. That's where the decisive messages are going to.
So now I have:
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stderr=subprocess.PIPE)
with open(self.logfilename, 'a+') as logfile:
logfile.write('%s\n%s\n' % ('*'*70, sourcefile))
for line in p.stderr.readlines():
logfile.write('%s\n' % line.strip())
and it's working fine.
ANOTHER EDIT
according to Didier's answer:
with sys.stdout = open(self.logfilename, 'w', 0) in my constructor:
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stdout=sys.stdout, stderr=sys.stdout)
There are several problems:
you should redirect both stdout and stderr
you should use unbuffered files if you want to mix normal print and the output of launched commands.
Something like this:
import sys, subprocess
# Note the 0 here (unbuffered file)
sys.stdout = open("mylog","w",0)
print "Hello"
print "-----"
subprocess.call(["./prog"],stdout=sys.stdout, stderr=sys.stdout)
print "-----"
subprocess.call(["./prog"],stdout=sys.stdout, stderr=sys.stdout)
print "-----"
print "End"
You need to redirect stderr too, you can use STDOUT or pass the file object to stderr=:
from subprocess import check_call,STDOUT
with open("log.txt","w") as f:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
check_call(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile],
stdout=f, stderr=STDOUT)
Try to redirect stdout and stderr to a logfile:
import subprocess
def analyseCpps(self):
with open("logfile.txt", "w") as logfile:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
call(['C:\\CodeAnalysis\\cppcheck\\cppcheck',
'--enable=all', sourcefile], stdout=logfile,
stderr=subprocess.STDOUT)
In this example the filename is hardcoded, but you should be able to change that easily (to your self.logfilename or similar).
I'm new to python, which I need to use for an assignment in a course. I developed the solution (an optimization algorithm) in Freemat / octave / matlab .m file and wanted to call it from Python (the python code will be called by a grading python script).
The .m file reads a file called tmp.data and writes the output to output.txt. The python script should then read from that output and convert it to the result that the grading script expects.
All runs fine, except I haven't been able to make Python wait for the call to Matlab to complete and therefore generates an error on the following lines.
Here's the code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from collections import namedtuple
Item = namedtuple("Item", ['index', 'value', 'weight'])
import subprocess
import os
from subprocess import Popen, PIPE
def solve_it(input_data):
# Modify this code to run your optimization algorithm
# Write the inputData to a temporay file
tmp_file_name = 'tmp.data'
tmp_file = open(tmp_file_name, 'w')
tmp_file.write(input_data)
tmp_file.close()
# call matlab (or any other solver)
# subprocess.call('matlab -r gp(\'tmp.data\')', shell=1)
# run=os.system
# a=run('matlab -r gp(\'tmp.data\')')
# process = Popen('matlab -r gp(\'tmp.data\')', stdout=PIPE)
# Popen.wait()
# (stdout, stderr) = process.communicate()
subprocess.call('matlab -r gp(\'tmp.data\')',shell=0)
# Read result from file
with open('output.txt') as f:
result = f.read()
# remove the temporay file
os.remove(tmp_file_name)
os.remove('output.txt')
return result
# return stdout.strip()
# prepare the solution in the specified output format
# output_data = str(value) + ' ' + str(0) + '\n'
# output_data += ' '.join(map(str, taken))
# return output_data
import sys
if __name__ == '__main__':
if len(sys.argv) > 1:
file_location = sys.argv[1].strip()
input_data_file = open(file_location, 'r')
input_data = ''.join(input_data_file.readlines())
input_data_file.close()
print solve_it(input_data)
else:
print 'This test requires an input file. Please select one from the data directory. (i.e. python solver.py ./data/ks_4_0)'
As you see, I've tried with subprocess.call, popen, os.system... to no avail. All of them give me similar errors:
C:\Users\gp\Documents\Documents\personal\educacion\Discrete Optimization\knapsack>python2 solver.py data/ks_19_0
Traceback (most recent call last):
File "solver.py", line 60, in <module>
print solve_it(input_data)
File "solver.py", line 30, in solve_it
with open('output.txt') as f:
IOError: [Errno 2] No such file or directory: 'output.txt'
Of course! The error comes while matlab is still in the process of opening. It thus is trying to access a file that hasn't been created yet.
What should I do to get Python to wait for Matlab to complete??
I appreciate your kind help, thanks.
[for the record]
As Daniel pointed out, it was solved by introducing a couple options into the matlab call:
subprocess.call('matlab -nosplash -wait -r "gp(\'tmp.data\')"',shell=0)
After that, it ran beautifully.
Thanks
Your code seems to irgnore the fact that matlab uses a launcher (matlab_root/bin/matlab.exe) and a main application (matlab_root/bin/xxx/matlab.exe). To keep the launcher open until the main application closes, you have to use the -wait option.
I'm trying to write a Python script that reads lines of strings from a file and executes a bash-shell command with each line as parameter:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
lines = [line.strip() for line in open('/tmp/i586rpm.txt')]
for rpm in lines:
try:
s = os.system("rpm -qip") % lines
except Exception:
print "Something wrong"
But I always get an error. I think that there is something wrong with % lines.
Any ideas?
Yes, you're not building the command string properly. Try:
s = os.system("rpm -qip \"%s\"" % rpm)
There are a few things that could be improved:
Uses os.system instead of subprocess.Popen (for more information, please have look at the documentation)
Iterates over lines, but it doesn't use the iteration variable (rpm)
Attemps to format the output string from os.system with lines as a parameter.
My advice is to use this code:
for line in lines:
p = subprocess.Popen('rpm -qip {0}'.format(line),
shell=True,
stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
instead of
for rpm in lines:
s = os.system("rpm -qip") % lines
do this
for rpm in lines:
s = os.system('rpm -qip "%s"' % rpm)
EDIT correct the code