Can anyone explain what is the difference between Popen and exec in Python
Im able to accomplish the same task to execute a program dynamically using exec and Popen.
The code here uses the EXEC approach but what will happen if I use the Popen approach.
code1.py
def runjob(src, job):
x = "from {src} import *" + '\n' + "{job}(parm1=)"
y = x.format(src=src, job=job)
exec ( 'from ' + src + ' import *' + '\n' + job + '(10)' )
def main():
runjob(c:/python27/test_job', 'il')
code2.py
def fl(parm=None):
print 'function1'
print parm
def f2(parm=None):
print 'function 2'
print parm
def f3(parm=None):
print 'function 3'
print parm
exec and Popen are more or less unrelated.
exec is used to run a piece of python code.
This statement supports dynamic execution of Python code. The first expression should evaluate to either a string, an open file object, or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error occurs). If it is an open file, the file is parsed until EOF and executed.
Popen is a class that allows to you to run any programm.
Execute a child program in a new process. It offers a lot of flexibility so that developers are able to handle the less common cases not covered by the convenience functions.
Not only can you run other programms, you can also read their output and set a number of usefull options, like the working directory or if a new terminal should be opened etc.
Related
I am working to convert a code which is written in a code called " elegant" into another code.
I come by this lines, which i could not understand well, i am quit new to python
import os,sys
def computeOpticsD(quad_name, quad_id,k1):
ex = '/Users/ia/Products/elegant/darwin-x86/elegant'
args = ' compute_optics_d.ele -macro=lattice=fodo,quad_name='+quad_name+',quad_id='+str(quad_id)+',k1='+str(k1)
args += ',dir=data'
os.system(ex + args)
What dose it exactly do ?
os.system allow you to run OS commands as you would do for example in a script or in the terminal directly.
For example, if you run os.system("ls") it will return the list of files and directories in the location
In this case it seems your code fragment is trying to execute the following command in the OS:
/Users/ia/Products/elegant/darwin-x86/elegant compute_optics_d.ele -macro=lattice={fodo}, quad_name={quad_name}, quad_id={quad_id}, k1={k1}, dir=data
Where the elemnts in the key brakets come from your method parameters as defined in: def computeOpticsD(quad_name, quad_id,k1)
I would like to write a python script which access the last command executed in terminal, i.e the command that launched the program.
For example, I want the terminal to output 'python myfile.py' if i typed python myfile.py
First I tried:
import os
os.system("touch command.txt")
os.system("history > command.txt")
with open("command.txt", "r") as f:
command = f.read()[-1]
print(command)
but this is not working since history is a bash built-in function.
Then I tried :
import os, subprocess
command = subprocess.check_output(["tail","-n","1",os.path.expanduser("~/.bash_history")]).decode("utf-8").rstrip()
print(command)
but this does not meet my expectations, because bash history is only updated when the terminal is closed.
To improve this behavior I tried os.putenv("PROMPT_COMMAND", "history-a"), but it didn't help neither, because bash history update is still one step behind, as my variable command would now contain the command line just before python myfile.py
Now I'm stuck and I need your help pls
You can't get the original shell command line in a reliable way without participation of the shell itself, but you can generate an equivalent command line using sys.argv. (It won't include things like redirections, but if you're just re-executing from inside the existing copy of the program, all those executions will have been already performed before you're started anyhow, so when you re-exec yourself the new copy will inherit their effect).
So:
#!/usr/bin/env python
import os.path, sys
try:
from shlex import quote # Python 3
except ImportError:
from pipes import quote # Python 2
sys_argv_str = ' '.join(quote(x) for x in sys.argv)
print("We can be restarted by calling the argv: %r" % (sys.argv,))
print("As a shell-syntax string, that would be: %s" % (sys_argv_str,))
print("...or, if your shell is bash, you can specify the interpreter directly:")
print(' ' + ' '.join(quote(x) for x in (['exec', '-a', sys.argv[0], os.path.abspath(sys.executable), os.path.abspath(__file__)] + sys.argv[1:])))
If someone calls ./yourprogram "first argument" "second argument", that output might look like:
We can be restarted by calling the argv: ['./yourprogram', 'first argument', 'second argument']
As a shell-syntax string, that would be: ./yourprogram 'first argument' 'second argument'
...or, if your shell is bash, you can specify the interpreter directly:
exec -a ./yourprogram /usr/bin/python /home/charles/tmp/yourprogram 'first argument' 'second argument'
Note that argv[0] is not guaranteed to be identical to __file__! When a program is starting another program it can pass any string it likes in the argv[0] slot; it's merely convention, not a firm guarantee, that that will contain the name that was used to start the software at hand.
I am revising a script that currently calls other scripts as subprocesses. Instead of doing that, I'm creating functions inside of the main script to perform the tasks previously performed by subprocesses.
One of the subprocesses required that variables be passed to it as you would from the command line.
Here is the code calling the subprocess:
subprocess.call("python cleaner.py < ./results/Temp.csv
>./results/result.csv", shell=True)
os.remove("./results/Temp.csv")
Here is what I'm trying to do:
def cleaner():
#working code that cleans certain characters out of selected
#.csv files.
function("./results/Temp.csv > ./results/result.csv", shell=True)
os.remove("./resluts/Temp.csv")
Ideally I'd like to use the existing code from the subprocess, but I'm open to changing it if that makes solving the problem easier. Here is that code:
from __future__ import print_function
from sys import stdin
print(next(stdin) , end='')
for line in stdin:
toks = [tok.replace("\'",""
).replace("text:u","").replace("number:", "") for tok in
line.split()]
print(' '.join(toks))
The script should clean the specified temp file, copy the cleaned version to a results file, then delete the temp file. Currently it works as a subprocess, but not when I try to run it as a function. I pass the variables incorrectly and it throws this error:
'TypeError: cleaner() takes no arguments (1 given)'
You need to define the arguments as part of the function.
def cleaner(argument1):
#working code that cleans certain characters out of selected
#.csv files.
Read more here.
This question already has answers here:
Retrieving the output of subprocess.call() [duplicate]
(7 answers)
Closed 7 years ago.
Newbie in python.
I'm trying to call a python script from a python script, for most of which I'm successful except capturing the result.
a.py
status = subprocess.call("python /hosting/apps/b.py"+" "+server+" "+port+" "+sid, shell=True)
b.py
Here in second script,I'm doing some computation and trying to pass back a variable named status using print and return
print status;
return status;
This doesn't seems to work. Is this the correct way of doing this?
You could use subprocess.check_output() rather than subprocess.call() to retrieve the content of the standard output (in which you have written with print and not return as BBrown noted) in a variable. This method is pretty general and is not limited to python scripts (you could call any accessible executable).
status = subprocess.check_output("python /hosting/apps/b.py"+" "+server+" "+port+" "+sid, shell=True)
However, you will retrieve the output as a string (everything that you printed during the execution of b.py) that you will need to parse. What you probably want to do is to define a function in the b.py module:
## b.py
def main(server, port, sid):
# Do things
return status
and call it from a.py (provided that b is in your sys.path):
## a.py
import b
status = b.main(server, port, sid)
The two options suggested in comments are probably your best bets. Here are small working examples:
Here, b.py sets status with the current time, and prints it.
b.py
import time
status = time.time()
print status
a.py (subprocess)
import subprocess
p = subprocess.Popen('python -u b.py', stdout=subprocess.PIPE)
(out,_) = p.communicate()
b_status = out
print b_status
Output:
1427685638.46
(Note, this extra space here is intended, b_status will have a trailing newline. This is something to keep in mind.)
a.py (import)
import b
b_status = b.status # Directly access b.py's status variable
print b_status
Output:
1427685801.45
1427685801.45
Note that status is displayed twice using the second method. Once in b.py's print status and once in a.py's print b_status. Don't let it confuse you, b_status contains only the timestamp, and no trailing newline like the first approach.
(In fact, it's "displayed" twice in the first method as well, but the output from b.py is captured by a.py, which is how b_status is set when using that approach.)
In general, I think importing is a better alternative, since printing and parsing it is much more error prone.
return won't return a value from a module (i.e. file); that's only for a function created with the def keyword. You could set the sys.stdout. See Redirect stdout to a file in Python? .
I'm trying to convert to get a command executed which is passed to the print statement. Eg:
print "exec(raw_input())"
Can I get to run the exec() in some way?
do this
command = raw_input("Command: ")
exec(command)
why are you trying to print it? be more clear if this isnt what you are looking for
I Guess this is what you are looking for ?
>>> exec("x = raw_input()")
23
>>> x
'23'
>>>
Are you asking for something simple like
aString = "raw_input()"
print "exec(" + aString + ")"
exec(aString)
from __future__ import print_function
def foo(x):
exec x
print = foo
print("exec(raw_input())")
Running
% test.py
kaboom
results in:
NameError: name 'kaboom' is not defined
From the tags you applied, it seems like you're looking for a magic string that will allow you to run any arbitrary code when Python passes that string to the print statement.
There are no such known strings. You might try very long strings, just over the obvious boundaries, looking for the traditional stack- and heap-overflow cases, but if you find one in Python X.Y.Z, chances are it was already fixed in X.Y.Z+1.
If the Python script is actually doing an exec or eval on your string, of course that's easy to exploit; if it's just doing a print, the contents never even get compiled, much less run; they're just a plain old string. The fact that the string happens to have dangerous-looking things like exec in it is irrelevant; it's not more exploitable than getting Python to print the string "rm -rf /".
Of course if you can arrange for the output of one Python interpreter to feed in as the input to an interactive session in another interpreter, then whatever you get the first interpreter to print will get executed in the second one… but in that case, you don't need the exec in the middle of the string anyway.
The print statement writes to sys.stdout by default, and sys.stdout is like a file. You can make a class that looks like a file, with a write method, which would be called by the print statement. I put together a script which demonstrates this, print_exec.py. Also note, this doesn't work if the code in the print statement contains print, itself. i.e., print "print 'foo'" won't work. So, in the example, I had to print to sys.stderr to actually see something happening. Hope this helps.
print_exec.py
import sys
class file_like(object):
def write(self, x):
exec(x)
sys.stdout = file_like()
y = "exec(raw_input())"
print "exec(y)"
Example running the print_exec.py:
>python print_exec.py
print "import sys; print >> sys.stderr, 'hi'"
hi
>