This question already has answers here:
How do I execute a program from Python? os.system fails due to spaces in path
(10 answers)
Closed 5 years ago.
Now Consider the following idea
I'm declaring a if/elif type to run the program
Such as :
number=int(input("Enter a number :"))
If number ==0
Run program.py
Elif number ==1
Run Program2.py
Else number ==2
Run Program3.py
Now clearly the command run program.py doesn't work so what should I do to make it execute program.py incase it is selected and close the main program where we are choosing the number?
There are several ways to run external code. There is subprocess and os.system() to run any other program on the disc, then there is exec to run a code you have as a string or code object, then there is eval that is kinda similar to exec but accepts only a string and allows to supply globals and locals. Those are all builtins.
But you probably don't really want to run external scripts as scripts. It creates all sorts of problems with correctly passing sys.argv to them, and making sure they get correct stdin/stdout and everything. Nine times out of ten you're better off creating a series of functions (perhaps in other files), importing them and calling those.
You should consider to learn about subprocesses: https://docs.python.org/3/library/subprocess.html
Popen option is one of the most useful ones for stuff like that.
number=int(input("Enter a number :"))
If number == 0:
subprocess.Popen([sys.argv[0], param])
Elif number ==1:
subprocess.Popen([program2.py, param])
Else number ==2:
subprocess.Popen([program3.py, param])
Note: Number 0 would open the same file you are using to call the new processes, just in case you ever need to "clone" your own program.
Edit: Linux and windows will require you to do this differently, as:
if platform.system() == "Linux":
subprocess.Popen([sys.argv[0], param])
else:
subprocess.Popen(["python", sys.argv[0], param])
Related
This question already has answers here:
assigning value to shell variable using a function return value from Python
(4 answers)
Closed 2 years ago.
I'm relatively new in shell scripting and I wanted to have some clarification on the following.
If i have a python script that does the following:
def return_output():
a = 1
b = 2
return a+b
if __name__ == "__main__":
return_output()
and say I want to run this script in bash in which I would want to retrieve the output value in bash via a variable:
summation=$(python total.py)
echo $summation
If i run the following shell script, nothing will be echoed.
However, i notice that when i change the python code of "return a+b" to "print(a+b)" instead, I would get the echoed value of "3" when i run the shell script.
3
Therefore my question is, if a python script were to be made to execute in a terminal, does it always have to print the output instead of using the return keyword?
Yes. Bash has no (simple) way to communicate with Python other than Python's stdout, so you will always have to print the output if you want bash to know what that output is.
Yes.
You'll want to print(...) (write to stdout) to capture the output of the script in a variable.
You can, in addition to that, call sys.exit(0), when the script ran successfully or, call sys.exit(1) if the script fails. This adheres to common UNIX CLI patterns.
I have tried my best to research and I have got to the point where I am using subprocess and subprocess.call to help me send my python variables to bash. I managed to get my python variables from bash output but now I need these variables to be in sync. I looked around couldn't learn how to use subprocess.call effectively. I have been using subprocess.check_output to obtain bash output into python variables flawlessly. I am having troubles understand how subprocess.call accepts arguments and how to use it properly. I tried following what I believed to be the correct format.
Here is my code. P.S I am brand new to joining this forum although I have been using it for tons of usefull information over the years. I dont know how to format my code input to look nice like how I see all over here. Regardless im sure you can forgive me as I tried the "Code" "Blockquotes" etc buttons.
###BEGINING OF CODE###
#! /usr/bin/env python2
import os,time,subprocess
#GRAB DATA
os.system('ifconfig > /tmp/ifconfig.txt;clear;cat /tmp/ifconfig.txt|grep "wlan"|cut -c 1-5 > /tmp/dev.lst;clear;')
#SET allwlan
allwlan=subprocess.check_output("cat /tmp/dev.lst", shell=True)
#SET max_index VARIABLE
max_index=subprocess.check_output("wc -l < /tmp/dev.lst", shell=True)
#SET curwlan WLAN LINE
#os.system(echo 2 > /tmp/curline.lst)
#STRIP DATA FOR curwlan
subprocess.call(['head', '-2', '/tmp/dev.lst', stdout=subprocess.PIPE, shell=True'])
#NEED#HELP#HERE# subprocess.call(['tail', '-1', > /tmp/curwlan.lst;')
#SET curwlan VARIABLE
curwlan=subprocess.check_output("cat /tmp/curwlan.lst", shell=True)
##STRIP EXCESS CHARACTERS/EMPTY LINES FROM VARIABLES##
curwlan=str(curwlan)
splitted=curwlan.split()
curwlan=splitted[0]
allwlan=allwlan[:-1]
splitted=max_index.split()
max_ index=splitted[0]
max_index=int(max_index)
##DEBUG MODE
print("Welcome, ")
print(" to debug mode. wireless adapter decting algorithm")
print
print("ALLWLAN:")
print(allwlan)
print
print("CURWLAN:")
print(curwlan)
print
print("MAX_INDEX:")
print(max_index)
print
input("PRESS ENTER TO EXIT")
####END OF CODE####*
The error in my code is under
#STRIP DATA FOR curwlan
Here is the output of that before I added the subprocess.call command.
Welcome,
to debug mode. wireless adapter decting algorithm
ALLWLAN:
wlan0
wlan3
CURWLAN:
wlan2
MAX_INDEX:
2
PRESS ENTER TO EXIT
I would love to learn how to have my python and bash parts communicate their variables together and I know I am on the right track with subprocess.call and ive been struggling for a few days now. I am trying to make my own algorithm to detect my wireless cards and be able to use each one (how ever many that may be or regardless what they may be named) as a variable for my
older scripts which now are struggling because of my constantly changing wireless card names. Thanks in advance I don't understand if what i'm asking subprocess.call to do is unrealistic or not.
You will want to avoid external processes as much as possible. Most of what you are doing is easy to do in just Python, and will be much more compact as well as more efficient if implemented natively.
Also, you are mixing the obsolete os.system() with subprocess where the latter is generally to be preferred, as also pointed out in the os.system() documentation.
subprocess.call() is only really appropriate when you don't expect any output from a command. The instance where you tried to use it, subprocess.check_output() would be the proper call to use. However, the places where you (as I understand, needlessly) ran shell commands with output to temporary files, you could have used subprocess.call(), trivially.
You need to understand when and where a shell is useful and necessary. Many places where you have shell=True would be more secure, faster, simpler, and more straightforward without a shell. Where you only run a simple hard-coded command with no redirection or globbing, switching from subprocess.whatever('command with args', shell=True) to subprocess.whatever(['command', 'with', 'args']) will instantly reduce your time and memory footprint with no ill effects. If you need redirection, pipelines, or globbing, maybe you want shell=True; but in many cases, doing those things in Python will be simple and straightforward. For example, here is how the head command could have been written without a shell:
with open('/tmp/randomfile', 'w') as outputfile:
subprocess.call(['head', '-n', '2', '/tmp/dev.lst'], stdout=outputfile)
Anyway, with these things out of the way, here is how I would do what (I think) you are attempting:
#!/usr/bin/env python2
import subprocess
allwlan = []
ifconfig = subprocess.check_output(['ifconfig'])
for line in ifconfig.split('\n'):
if "wlan" in line:
allwlan.append(line[0:5].strip())
max_index=len(allwlan)
curwlan=allwlan[1]
This was hastily thrown together, but I believe I captured at least most of what your current pretzel logic code does; though I have assumed that sprinkling the /tmp file system with random output files was not an essential feature of your script.
Thank you all for your advice. My script has come along way; Here is what this part looks like, over 1 year later,
def detmon():
try:
subprocess.call(['clear'])
item = []
items = []
the_choice = []
iwconfig = subprocess.check_output(['iwconfig'])
for line in iwconfig.split():
if "mon" in line:
items.append(line.strip(':'))
subprocess.call(['clear'])
max_index=len(items)-1
#items=items[counter]
#Print Files List
for item in items:
print(" ", items.index(item), ": ", item)
os.system('echo "\n"')
print(len(items))
try:
if len(items) >= 0:
counter = 0
allmon = []
ifconfig = subprocess.check_output(['iwconfig'])
for line in ifconfig.split():
if "mon" in line:
allmon.append(line.strip(':'))
subprocess.call(['clear'])
max_index=len(allmon)
curmon=allmon[counter]
while counter <= max_index:
curmon=allmon[counter]
subprocess.call(['airmon-ng', 'stop', curmon])
counter += 1
else:
print("No more 'mon' interfaces are found")
except:
print("No more 'mon' interfaces are found")
except KeyboardInterrupt:
pass
This question already has answers here:
Disable output buffering
(16 answers)
Closed 8 years ago.
I have a python script that looks something like this:
for item in collection:
print "what up"
#do complicated stuff that takes a long time.
In bash, I run this script by doing the following:
$ python my.py | tee my_file.txt
However, all I see in bash is a blank line until the program finishes. Then, all of the print statements come all at one.
Is this the expected operation of tee? Can I use tee to see the output in real-time?
Python, like many programs, tries to minimize the number of times it calls the write system call. It does this by collecting the output of several print statements before it actually writes them to its standard output file. This process is called buffering the output.
When Python is connected to a terminal, it doesn't buffer its output. This makes sense, because the human at the terminal wants to see the output right away.
When Python is writing to a file (or a pipe), it does buffer its output. This also makes sense, because no one will see the output until the process is complete
You can defeat this optimization by calling sys.stdout.flush() whenever you want to force Python to write its buffered output to its standard output file.
In your case, try this:
import sys
...
for item in collection:
print "what up"
sys.stdout.flush()
#do complicated stuff that takes a long time.
This question already has answers here:
How to keep a Python script output window open?
(27 answers)
Closed 9 years ago.
I am trying to learn python and for that purpose i made a simple addition program using python 2.7.3
print("Enter two Numbers\n")
a = int(raw_input('A='))
b = int(raw_input('B='))
c=a+b
print ('C= %s' %c)
i saved the file as add.py and when i double click and run it;the program run and exits instantenously without showing answer.
Then i tried code of this question Simple addition calculator in python it accepts user inputs but after entering both numbers the python exits with out showing answer.
Any suggestions for the above code. Advance thanks for the help
add an empty raw_input() at the end to pause until you press Enter
print("Enter two Numbers\n")
a = int(raw_input('A='))
b = int(raw_input('B='))
c=a+b
print ('C= %s' %c)
raw_input() # waits for you to press enter
Alternatively run it from IDLE, command line, or whichever editor you use.
It's exiting because you're not telling the interpreter to pause at any moment after printing the results. The program itself works. I recommend running it directly in the terminal/command line window like so:
Alternatively, you could write:
import time
print("Enter two Numbers\n")
a = int(raw_input('A='))
b = int(raw_input('B='))
c=a+b
print ('C= %s' %c)
time.sleep(3.0) #pause for 3 seconds
Or you can just add another raw_input() at the end of your code so that it waits for input (at which point the user will type something and nothing will happen to their input data).
Run your file from the command line. This way you can see exceptions.
Execute cmd than in the "dos box" type:
python myfile.py
Or on Windows likley just:
myfile.py
This question already has answers here:
What is the best way to call a script from another script? [closed]
(16 answers)
Closed 8 years ago.
I want to run a Python script from another Python script. I want to pass variables like I would using the command line.
For example, I would run my first script that would iterate through a list of values (0,1,2,3) and pass those to the 2nd script script2.py 0 then script2.py 1, etc.
I found Stack Overflow question 1186789 which is a similar question, but ars's answer calls a function, where as I want to run the whole script, not just a function, and balpha's answer calls the script but with no arguments. I changed this to something like the below as a test:
execfile("script2.py 1")
But it is not accepting variables properly. When I print out the sys.argv in script2.py it is the original command call to first script "['C:\script1.py'].
I don't really want to change the original script (i.e. script2.py in my example) since I don't own it.
I figure there must be a way to do this; I am just confused how you do it.
Try using os.system:
os.system("script2.py 1")
execfile is different because it is designed to run a sequence of Python statements in the current execution context. That's why sys.argv didn't change for you.
This is inherently the wrong thing to do. If you are running a Python script from another Python script, you should communicate through Python instead of through the OS:
import script1
In an ideal world, you will be able to call a function inside script1 directly:
for i in range(whatever):
script1.some_function(i)
If necessary, you can hack sys.argv. There's a neat way of doing this using a context manager to ensure that you don't make any permanent changes.
import contextlib
#contextlib.contextmanager
def redirect_argv(num):
sys._argv = sys.argv[:]
sys.argv=[str(num)]
yield
sys.argv = sys._argv
with redirect_argv(1):
print(sys.argv)
I think this is preferable to passing all your data to the OS and back; that's just silly.
Ideally, the Python script you want to run will be set up with code like this near the end:
def main(arg1, arg2, etc):
# do whatever the script does
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2], sys.argv[3])
In other words, if the module is called from the command line, it parses the command line options and then calls another function, main(), to do the actual work. (The actual arguments will vary, and the parsing may be more involved.)
If you want to call such a script from another Python script, however, you can simply import it and call modulename.main() directly, rather than going through the operating system.
os.system will work, but it is the roundabout (read "slow") way to do it, as you are starting a whole new Python interpreter process each time for no raisin.
I think the good practice may be something like this;
import subprocess
cmd = 'python script.py'
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate()
result = out.split('\n')
for lin in result:
if not lin.startswith('#'):
print(lin)
according to documentation
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:
os.system
os.spawn*
os.popen*
popen2.*
commands.*
Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.
Read Here
SubProcess module:
http://docs.python.org/dev/library/subprocess.html#using-the-subprocess-module
import subprocess
subprocess.Popen("script2.py 1", shell=True)
With this, you can also redirect stdin, stdout, and stderr.
import subprocess
subprocess.call(" python script2.py 1", shell=True)