I would like to invoke multiple commands from my python script.
I tried using the os.system(), however, I'm running into issues when the current directory is changed.
example:
os.system("ls -l")
os.system("<some command>") # This will change the present working directory
os.system("launchMyApp") # Some application invocation I need to do.
Now, the third call to launch doesn't work.
os.system is a wrapper for the C standard library function system(). Its argument can be any valid shell command as long as it fits into the memory reserved for environment and argument lists of a process.
So, delimit each command with a semicolon or a newline and they will be executed one after another in the same environment.
os.system(" ls -l; <some command>; launchMyApp")
os.system('''
ls -l
<some command>
launchMyApp
''')
Try this
import os
os.system("ls -l")
os.chdir('path') # This will change the present working directory
os.system("launchMyApp") # Some application invocation I need to do.
Each process has its own current working directory. Normally, child processes can't change parent's directory that is why cd is a builtin shell command: it runs in the same (shell) process.
Each os.system() call creates a new shell process. Changing the directory inside these processes has no effect on the parent python process and therefore on the subsequent shell processes.
To run multiple commands in the same shell instance, you could use subprocess module:
#!/usr/bin/env python
from subprocess import check_call
check_call(r"""set -e
ls -l
<some command> # This will change the present working directory
launchMyApp""", shell=True)
If you know the destination directory; use cwd parameter suggested by #Puffin GDI instead.
It’s simple, really.
For Windows separate your commands with &, for Linux, separate them with ;.
str.replace is a very good way to approach the problem, used in the example below:
import os
os.system('''cd /
mkdir somedir'''.replace('\n', ';')) # or use & for Windows
When you call os.system(), every time you create a subshell - that closes immediately when os.system returns (subprocess is the recommended library to invoke OS commands). If you need to invoke a set of commands - invoke them in one call.
BTW, you may change working director from Python - os.chdir
Try to use subprocess.Popen and cwd
example:
subprocess.Popen('launchMyApp', cwd=r'/working_directory/')
os.system("ls -l && <some command>")
You can change back to the directory you need to be in with os.chdir()
Just use
os.system("first command\nsecond command\nthird command")
I think you have got the idea what to do
Note: This is not a very reliable approach if you are doing a complex
job using CLI tools. Popen and subprocess methods are better there.
Although small task link copy, move, list will work fine
.
Related
I have a virtualenv named 'venv' and it is activate:
(venv)>
and I wrote codes that I'll run it in the virtualenv (main.py):
import subprocess
result = subprocess.run('python other.py', stdout=subprocess.PIPE)
but when I run main.py file:
(venv)> python main.py
subprocess does not execute the command (python other.py) in the virtualenv i.e venv
How to run subprocess command in the current virtualenv session?
A child process can't run commands in its parent process without that process's involvement.
This is why ssh-agent requires usage as eval "$(ssh-agent -s)" to invoke the shell commands it emits on output, for example. Thus, the literal thing you're asking for here is impossible.
Fortunately, it's also unnecessary.
virtualenvs use environment variables inherited by child processes.
This means that you don't actually need to use the same shell that has a virtualenv activated to start a new Python interpreter intended to use the interpreter/libraries/etc. from that virtualenv.
subprocess.run must be passed a list, or shell=True must be used.
Either do this (which is better!)
import subprocess
result = subprocess.run(['python', 'other.py'], stdout=subprocess.PIPE)
Or this (which is worse!)
import subprocess
result = subprocess.run('python other.py', stdout=subprocess.PIPE, shell=True)
If you want to run a script with the same Python executable being used to run the current script, don't use python and rely on the path being set up properly, just use sys.executable:
A string giving the absolute path of the executable binary for the Python interpreter, on systems where this makes sense.
This works if you executed the script with python myscript.py relying on the active virtualenv's PATH. It also works if you executed the script with /usr/local/bin/python3.6 to ignore the PATH and test your script with a specific interpreter. Or if you executed the script with myscript.py, relying on a shbang line created at installation time by setuptools. Or if the script was run as a CGI depending on your Apache configuration. Or if you sudod the executable, or did something else that scraped down your environment. Or almost anything else imaginable.1
As explained in Charles Duffy's answer, you still need to use a list of arguments instead of a string (or use shell=True, but you rarely want to do that). So:
result = subprocess.run([sys.executable, 'other.py'], stdout=subprocess.PIPE)
1. Well, not quite… Examples of where it doesn't work include custom C programs that embed a CPython interpreter, some smartphone mini-Python environments, old-school Amiga Python, … The one most likely to affect you—and it's a pretty big stretch—is that on some *nix platforms, if you write a program that execs Python by passing incompatible names for the process and arg0, sys.executable can end up wrong.
I want to write a python program that runs in the background.
I mean, like we install Python package. And later, we can run any script using python in front of the script name. This means that some python process is running in background which can take inputs and perform actions.
And in case of linux, you can call grep from anywhere. That means grep is also running in the background somehow.
I want to write something like that in python. When I call certain function with name and arguments at any time, it should perform the intended action without caring for the original code. But I am not able to find how to achieve that.
Can anyone please help me here?
Thanks in advance.
Clarification: the fact that you can run python or grep in a console just by typing their name, does not mean that they run in background. It means that there exist an executable file in some location, and this location is listed in the environment variable PATH.
For example, on my system I can run Python by typing python. The python executable is installed at /usr/local/bin/python, and has the execute permission bit on.
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin
and yes, /usr/local/bin is contained in PATH.
You can do the same with python scripts:
ensure that the very first line of your script contains #!/usr/bin/python or #!/usr/bin/env python
give your script execute permissions: chmod a+x yourScript
either move your script to one of the directories contained in $PATH, or add the directory where your script is located to PATH: export PATH=$PATH:/home/you/scripts
Have a look at
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
you can roll out your own daemon by inheriting the Daemon class and overriding run method
from daemon import Daemon
class run_daemon(Daemon):
def run(self):
import sys
run_daemon.execute_shell_command(sys.argv[1])
#staticmethod
def execute_shell_command(ShellCommand):
import subprocess
process = subprocess.Popen(ShellCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.communicate()
I am looking to open a Python script in edit mode in IDLE by passing in a directory from another Python script. I understand that I can use os.system to execute idle.py but I then don't know how to pass the appropriate -e parameter and get it to use a specific directory i.e. open something.py in diredtory C:\Python all from the original Python script.
Thanks for your help,
Ben
You can use subprocess.call(). By setting shell = True, the function treats the string as a literal shell command. Modify the paths as you see fit.
import subprocess
subprocess.call(r'C:\Python27\Lib\idlelib\idle.py -e C:\Python27\something.py',
shell=True)
I need to execute the simple command below in windows 7 command prompt using Python26.
cd C:\Python26\main project files\Process
C:\Aster\runtime\waster Analysis.comm
It runs a FEM simulation and I tried it manually and it worked well. Now, I want to automate the write procedure using Python26.
I studied the other questions and found that the os.system works but it didn't. Also I saw subprocess module but it didn't work.
The current directory is a process property: Every single process has its own current directory. A line like
os.system("cd xyz")
starts a command interpreter (cmd.exe on Windows 7) and execute the cd command in this subprocess, not affecting the calling process in any way. To change the directory of the calling process, you can use os.chdir() or the cwd keyword parameter to subprocess.Popen().
Example code:
p = subproces.Popen(["C:/Aster/runtime/waster", "Analysis.comm"],
cwd="C:/Python26/main project files/Process")
p.wait()
(Side notes: Use forward slashes in path names in Python files. You should avoid os.system() and passing shell=True to the function in the subprocess module unless really necessary.)
Is it possible to change the Windows command prompt working directory via Python script?
e.g.
>> cd
>> c:\windows\system32
>> make_decision_change_dir.py
>> cd
>> c:\windows
I have tried a few things which don't work:
import os
os.chdir(path)
import os, subprocess
subprocess.Popen("chdir /D \"%s\"" %path, shell=True)
import os, subprocess
subprocess.Popen("cd \"%s\"" %path, shell=True)
import os, subprocess
subprocess.Popen("CD=\"%s\"" %path, shell=True)
As I understand it and observe these operations change the current processes working directory - which is the Python process and not the prompt its executing from.
Thanks.
UPDATE
The path I would want to change to is dynamic (based on what project I am working on, the full path to a build location changes) hence I wanted to code a solution in Python rather than hack around with a Windows batch file.
UPDATE
I ended up hacking a batch file together to do this ;(
Thanks everyone.
I'm not clear what you want to do here. Do you want a python script which you can run from a Windows command prompt which will change the working directory of the Windows command session?
If so, I'm 99.9% sure that's impossible. As you said yourself the python.exe process is a separate process from the Windows cmd.exe and anything you do in Python won't affect the Command prompt.
There may be something you can do via the Windows API by sending keystrokes to the Windows or something but it would be pretty brittle.
The only two practical options I can think of involve wrapping your Python script in a Batch file:
Output your desired directory from the Python script, read the output in your Batch file and CD to it.
Start your Python script from a batch file, allow your Python script to start a new cmd.exe Window and get the Batch file to close the original Command window.
I have a Python script to make moving around a file tree easier: xdir.py
Briefly, I have an xdir.py file, which writes Windows commands to stdout:
# Obviously, this should be more interesting..
import sys
print "cd", sys.argv[1]
Then an xdir.cmd file:
#echo off
python xdir.py %* >%TEMP%\__xdir.cmd
call %TEMP%\__xdir.cmd
Then I create a doskey alias:
doskey x=xdir.cmd $*
The end result is that I can type
$ x subdir
and change into subdir.
The script I linked to above does much more, including remembering history, maintaining a stack of directories, accepting shorthand for directories, and so on.
One common solution is a two-part script.
Part 1 is Python, which creates a temporary .BAT file that contains the appropriate CD command.
Part 2 is the temporary .BAT file.
fancycd.bat
python figurethepath.py >temp.bat
temp.bat
As people mentioned, child processes (i.e. your program) can't change the current working directory of a parent process (i.e. the terminal). This is why you need the two steps that everybody is describing. In most shells there's a way to make a macro or function to perform this two-step functionality.
For example, in bash, you can make a single alias to compute the path and change the current working directory, similar to what #S.Lott describes for Windows:
alias my_cd='TMP=`compute_path.py`; cd $TMP;'
Note that the cd command is still being interpreted in the parent process (the terminal), which has the ability to change its own current working directory.
The subprocess.Popen() doc page says a child process will be created for the sub-process, so any working directory changes will be local to that subprocess.
If cwd is not None, the child’s current directory will be changed to cwd before it is executed. Note that this directory is not considered when searching the executable, so you can’t specify the program’s path relative to cwd.
This will be the same for any changes done explicitly inside the subproceess, similar to the commands that appear in the question.
imoprt os
os.system("start cmd.exe /k \"cd /d c:\\windows\\system32 & python make_decision_change_dir.py\"")