When this .exe file runs it prints a screen full of information and I want to print a particular line out to the screen, here on line "6":
cmd = ' -a ' + str(a) + ' -b ' + str(b) + str(Output)
process = Popen(cmd, shell=True, stderr=STDOUT, stdout=PIPE)
outputstring = process.communicate()[0]
outputlist = outputstring.splitlines()
Output = outputlist[5]
print cmd
This works fine:
cmd = ' -a ' + str(a) + ' -b ' + str(b)
This doesn't work:
cmd = ' -a ' + str(a) + ' -b ' + str(b) + str(Output)
I get an error saying Output isn't defined. But when I cut and paste:
outputstring = process.communicate()[0]
outputlist = outputstring.splitlines()
Output = outputlist[5]
before the cmd statement it tells me the process isn't defined. str(Output) should be what is printed on line 6 when the .exe is ran.
You're trying to append the result of a call into the call itself. You have to run the command once without the + str(Output) part to get the output in the first place.
Think about it this way. Let's say I was adding some numbers together.
z = 5 + b
b = z + 2
I have to define either z or b before the statements, depending on the order of the two statements. I can't use a variable before I know what it is. You're doing the same thing, using the Output variable before you define it.
It's not supposed to be a "dance" to move things around. It's a matter of what's on the left side of the "=". If it's on the left side, it's getting created; if it's on the right side it's being used.
As it is, your example can't work even a little bit because line one wants part of output, which isn't created until the end.
The easiest way to understand this is to work backwards. You want to see as the final result?
print output[5]
Right? So to get there, you have to get this from a larger string, right?
output= outputstring.splitlines()
print output[5]
So where did outputstring come from? It was from some subprocess.
outputstring = process.communicate()[0]
output= outputstring.splitlines()
print output[5]
So where did process come from? It was created by subprocess Popen
process = Popen(cmd, shell=True, stderr=STDOUT, stdout=PIPE)
outputstring = process.communicate()[0]
output= outputstring.splitlines()
print output[5]
So where did cmd come from? I can't tell. Your example doesn't make sense on what command is being executed.
cmd = ?
process = Popen(cmd, shell=True, stderr=STDOUT, stdout=PIPE)
outputstring = process.communicate()[0]
output= outputstring.splitlines()
print output[5]
Just change your first line to:
cmd = ' -a ' + str(a) + ' -b ' + str(b)
and the print statement at the end to:
print cmd + str(Output)
This is without knowing exactly what it is you want to print...
It -seems- as if your problem is trying to use Output before you actually define what the Output variable is (as the posts above)
Like you said, a variable has to be declared before you can use it. Therefore when you call str(Output) ABOVE Output = outputlist[5], Output doesn't exist yet. You need the actually call first:
cmd = ' -a ' + str(a) + ' -b ' + str(b)
then you can print the output of that command:
cmd_return = ' -a ' + str(a) + ' -b ' + str(b) + str(Output)
should be the line directly above print cmd_return.
Related
Since hours I try to solve this problem - hope anybody can help me. I parse a hex number out of the output of a program, which I run via Popen in Python. In the next step, this hex number is used as parameter for another call of the program via Popen. The problem is, that I am not able to pass the hex value to Popen, so that it works:
cmd = "./my_program"
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
response = p.stdout.read()
hexapattern = r'0x([0-9a-fA-F]+)'
hex_output = re.findall(hexapattern, str(response))[1] #e.g.: hex_string = 35fe9a30
hex_string = '\\x' + hex_output[6] + hex_output[7] + '\\x' + hex_output[4] + hex_output[5] + '\\x' + hex_output[2] + hex_output[3] + '\\x' + hex_output[0] + hex_output[1] #e.g.: hex_string = \x35\xfe\9a\x30
payload = '\x41\x41\x41' + hex_string
cmd = "echo -e -n " + payload + " | ./my_program"
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
response = p.stdout.read()
print(response)
The following line does not work the way it should. While the first part of the string is correctly interpreted (as 'AAA', ASCII character with number 41), the 'hex_string' is used in bash as '\x35\xfe\9a\x30'. It is not a problem, that some chars are not printable.
payload = '\x41\x41\x41' + hex_string
Output: AAA\x35\xfe\9a\x30
When I change the program to set the value manually to the variable (I don't want to do this), it works without any problems.
payload = '\x41\x41\x41' + '\x35\xfe\9a\x30'
Output: AAA[not printable char][not printable char][not printable char]
I already tried a lot of type conversions but failed.
ast.literal_eval is a way to make the string like if you typed it literally.
hex_output = "35fe9a30"
hex_string = '\\x' + hex_output[6] + hex_output[7] + '\\x' + hex_output[4] + hex_output[5] + '\\x' + hex_output[2] + hex_output[3] + '\\x' + hex_output[0] + hex_output[1] #e.g.: hex_string = \x35\xfe\9a\x30
payload = '\x41\x41\x41' + hex_string
import ast
result = ast.literal_eval('"{}"'.format(payload))
print('\x41\x41\x41' + '\x30\x9a\xfe\x35' == result)
prints True (note that hex_string is the reverted version of hex_output, which doesn't simplify the example...)
We just told ast.literal_eval to evaluate the string (hence the formatting with quotes) containing payload
There may be simpler solutions with codec, handling the whole data as bytes instead of str:
import codecs
print(b'\x41\x41\x41' + codecs.decode(hex_output.encode(),"hex"))
prints:
b'AAA5\xfe\x9a0'
Is there a more elegant way of comparing these two files?
Right now I am getting the following error message: syntax error near unexpected token (... diff <( tr -d ' '.
result = Popen("diff <( tr -d ' \n' <" + file1 + ") <( tr -d ' \n' <"
+ file2 + ") | wc =l", shell=True, stdout=PIPE).stdout.read()
Python seems to read "\n" as a literal character.
The constructs you are using are interpreted by bash and do not form a standalone statement that you can pass to system() or exec().
<( ${CMD} )
< ${FILE}
${CMD1} | ${CMD2}
As such, you will need to wire-up the redirection and pipelines yourself, or call on bash to interpret the line for you (as #wizzwizz4 suggests).
A better solution would be to use something like difflib that will perform this internally to your process rather than calling on system() / fork() / exec().
Using difflib.unified_diff will give you a similar result:
import difflib
def read_file_no_blanks(filename):
with open(filename, 'r') as f:
lines = f.readlines()
for line in lines:
if line == '\n':
continue
yield line
def count_differences(diff_lines):
diff_count = 0
for line in diff_lines:
if line[0] not in [ '-', '+' ]:
continue
if line[0:3] in [ '---', '+++' ]:
continue
diff_count += 1
return diff_count
a_lines = list(read_file_no_blanks('a'))
b_lines = list(read_file_no_blanks('b'))
diff_lines = difflib.unified_diff(a_lines, b_lines)
diff_count = count_differences(diff_lines)
print('differences: %d' % ( diff_count ))
This will fail when you fix the syntax error because you are attempting to use bash syntax in what is implemented as a C system call.
If you wish to do this in this way, either write a shell script or use the following:
result = Popen(['bash', '-c',
"diff <( tr -d ' \n' <" + file1 + ") <( tr -d ' \n' <"
+ file2 + ") | wc =l"], shell=True, stdout=PIPE).stdout.read()
This is not an elegant solution, however, since it is relying on the GNU coreutils and bash. A more elegant solution would be pure Python. You could do this with the difflib module and the re module.
Here is the except of my code related to this:
def grd_commands(directory):
for filename in os.listdir(directory)[1:]:
print filename
new_filename = ''
first_letter = ''
second_letter = ''
bash_command = 'gmt grdinfo ' + filename + ' -I-'
print bash_command
coordinates = Popen(bash_command, stdout=PIPE, shell=True)
coordinates = coordinates.communicate()
latlong = re.findall(r'^\D*?([-+]?\d+)\D*?[-+]?\d+\D*?([-+]?\d+)', coordinates)
if '-' in latlong[1]:
first_letter = 'S'
else:
first_letter = 'N'
if '-' in latlong[0]:
second_letter = 'W'
else:
second_letter = 'E'
new_filename = first_letter + str(latlong[1]) + second_letter + str(latlong[0]) + '.grd'
Popen('gmt grdconvert ' + str(filename) + ' ' + new_filename, shell=True)
filenameis the name of the file that is is being passed to the function. When I run my code, I am receiving this error:
/bin/sh: gmt: command not found
Traceback (most recent call last):
File "/Users/student/Desktop/Code/grd_commands.py", line 38, in <module>
main()
File "/Users/student/Desktop/Code/grd_commands.py", line 10, in main
grd_commands(directory)
File "/Users/student/Desktop/Code/grd_commands.py", line 23, in grd_commands
latlong = re.findall(r'^\D*?([-+]?\d+)\D*?[-+]?\d+\D*?([-+]?\d+)', coordinates).split('\n')
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/re.py", line 177, in findall
return _compile(pattern, flags).findall(string)
TypeError: expected string or buffer
If I print out the string bash_command and try entering it into terminal it fully functions. Why doesn't it work when being called by my Python script?
The entire command line is being treated as a single command name. You need to either use shell=True to have the shell parse it as a command line:
coordinates = Popen(bash_command, stdout=PIPE, shell=True)
or preferably store the command name and its arguments as separate elements of a list:
bash_command = ['gmt', 'grdinfo', filename, '-I-']
coordinates = Popen(bash_command, stdout=PIPE)
Popen takes a list of arguments. There is a warning for using shell=True
Passing shell=True can be a security hazard if combined with untrusted input.
Try this:
from subprocess import Popen, PIPE
bash_command = 'gmt grdinfo ' + filename + ' -I-'
print(bash_command)
coordinates = Popen(bash_command.split(), stdout=PIPE)
print(coordinates.communicate()[0])
Ensure gmt is installed in a location specified by PATH in your /etc/environment file:
PATH=$PATH:/path/to/gmt
Alternatively, specify the path to gmt in bash_command:
bash_command = '/path/to/gmt grdinfo ' + filename + ' -I-'
You should be able to find the path with:
which gmt
As other people have suggested, an actual list would be the best approach instead of a string. Additionally, you must escape spaces with a '\' in order to actually access the file if there is a space in it.
for filename in os.listdir(directory)[1:]:
bash_command = ['gmt', 'grdinfo', filename.replace(" ", "\ "), '-I-']
I'm trying to run Zenity in a python script, to display a variable.
nmaj = 10
cmd = ["zenity" "--question" "--text='Are you " + str(nmaj) + "years old ?'"]
subprocess.call(cmd, shell=True)
Can I put a string in the command? How?
Thanks
You can try using format and putting '' outer than "":
nmaj = 10
cmd = 'zenity --question --text="Are you {} years old ?"'.format(nmaj)
subprocess.call(cmd, shell=True)
You miss comma(,)s between command line arguments:
cmd = ["zenity", "--question", "--text='Are you " + str(nmaj) + "years old ?'"]
Otherwise the string literals are concatenated into a string (See String literal concatenation):
>>> "zenity" "--question" "--text='Are you "
"zenity--question--text='Are you "
I'm running a script to feed an exe file a statement like below:
for j in ('90.','52.62263.','26.5651.','10.8123.'):
if j == '90.':
z = ('0.')
elif j == '52.62263.':
z = ('0.', '72.', '144.', '216.', '288.')
elif j == '26.5651':
z = ('324.', '36.', '108.', '180.', '252.')
else:
z = ('288.', '0.', '72.', '144.', '216.')
for k in z:
exepath = os.path.join('\Program Files' , 'BRL-CAD' , 'bin' , 'rtarea.exe')
exepath = '"' + os.path.normpath(exepath) + '"'
cmd = exepath + '-j' + str(el) + '-k' + str(z)
process=Popen('echo ' + cmd, shell=True, stderr=STDOUT )
print process
I'm using the command prompt and when I run the exe with these numbers there are times when It doesn't seem to be in order. Like sometimes it will print out 3 statements of the 52.62263 but then before they all are printed it will print out a single 26.5651 and then go back to 52.62263. It's not just those numbers that act like this. Different runs it may be different numbers (A 52.62263 between "two" 90 statements) . All in all, I want it to print it in order top to bottom. Any suggestions and using my code any helpful solutions? thanks!
z = ('0.') is not a tuple, therefore your for k in z loop will iterate over the characters "0" and ".". Add a comma to tell python you want it to be a tuple:
z = ('0.',)
I think what's happening right now is that you are not waiting for those processes to finish before they're printed. Try something like this in your last 2 lines:
from subprocess import Popen, STDOUT
stdout, stderr = Popen('echo ' + cmd, shell=True, stderr=STDOUT).communicate()
print stdout
What eduffy said. And this is a little cleaner; just prints, but you get the idea:
import os
data = {
'90.': ('0.',),
'52.62263.': ('0.', '72.', '144.', '216.', '288.'),
'26.5651.': ('324.', '36.', '108.', '180.', '252.'),
'10.8123.': ('288.', '0.', '72.', '144.', '216.'),
}
for tag in data:
for k in data[tag]:
exepath = os.path.join('\Program Files', 'BRL-CAD', 'bin', 'rtarea.exe')
exepath = '"' + os.path.normpath(exepath) + '"'
cmd = exepath + ' -el ' + str(tag) + ' -az ' + str(data[tag])
process = 'echo ' + cmd
print process
Since you've made a few posts about this bit of code, allow me to just correct/pythonify/beautify the whole thing:
for j,z in {
'90.' : ('0.',) ,
'52.62263.' : ('0.', '72.', '144.', '216.', '288.') ,
'26.5651.' : ('324.', '36.', '108.', '180.', '252.') ,
'10.8123.' : ('288.', '0.', '72.', '144.', '216.')
}.iteritems():
for k in z:
exepath = os.path.join('\Program Files' , 'BRL-CAD', 'bin' , 'rtarea.exe')
exepath = '"%s"' % os.path.normpath(exepath)
cmd = exepath + '-j' + str(el) + '-k' + z
process = Popen('echo ' + cmd, shell=True, stderr=STDOUT )
print process