This question already has answers here:
Equivalent of shell 'cd' command to change the working directory?
(14 answers)
Can the child process affect parent process' environment?
(3 answers)
Closed 9 months ago.
I want to run cd command in the terminal through my Python script. I just discovered a module called subprocess, do you have any idea why the Popen() method doesn't change the directory in the terminal, it seems like it changes the state only.
if p:
return subprocess.Popen(['cd'], cwd = target_dir, shell = True)
return 'directory does not exist'
Terminal:
<subprocess.Popen object at 0x7f805ef045e0>
When I changed the command, it seems working:
if p:
return subprocess.Popen(['ls', '-a'], cwd = target_dir, shell = True)
return 'directory does not exist'
Terminal:
<subprocess.Popen object at 0x7ff1ef1ec5e0>
. .. projects books resources docs
Your help is much appreciated!
subprocess module creates new sub process and changes directory in for that process. it will not change directory of the parent process.
To change current process directory use os.chdir(target_dir)
More:
import os
os.chdir(<target_dir>) # to change directory
os.listdir('.') # to list current directory
os.listdir(<target_idr>) # to list target_dir
dirA/dirB/dirC/program.py
dirA/dirD/target.py
How can I initiate the execution of target.py by program.py? I tried to use os.startfile(".\.\.\dirD\target.py") but unfortunately, it does not work. Have not found anything which helped.
Program.py should be closed. Also, it should be based on a relative path since the scripts will be used on multiple machines!
Use subprocess.Popen, and invoke it with python.
import subprocess as sp
sp.Popen(['python', r'../target.py'])
If you use Popen as the last line that is executed in program.py, the new script will be started and the program.py will exit.
Note that you can use os.path.abspath() to turn a relative path into an absolute path if necessary.
I found a solution using the pathlib-module and os.startfile().
pathlib.Path(__file__).parent.parent returns the desired directory so that os.startfile(str(pathlib.Path(file).parent) + [path]) executes the file.
I have converted my python program to exe using pyinstaller. My exe creates a temporary folder _MEIxxxxx to keep files. In the same folder there is a file which is being changed by the program, but unfortunately it is not happening.
In the program I change the folder to go to above folder:
os.chdir('C:\\Users\\Public')
for foldername in os.listdir():
if foldername.startswith('_MEI'):
myfolder = foldername
os.chdir('C:\\Users\\Public'+myfolder+'\\Quiz')
Thanks in advance.
this doesn't work:
os.chdir('C:\\Users\\Public'+myfolder+'\\Quiz')
because myfolder doesn't contain a \ at start.
Don't hardcode C:\Users\Public, use PUBLIC env. var
And avoid chdir, it's equivalent as a global variable shared between all modules. What if some module needs one current dir, and the other another?
Your attempt looks more like a shell script ported to python cd xxx; ls; .... Break this habit.
Use absolute paths/paths passed as parameter instead. My proposal:
pubdir = os.getenv("PUBLIC")
for foldername in os.listdir(pubdir):
if foldername.startswith('_MEI'):
myfolder = foldername
quizdir = os.path.join(pubdir,myfolder,'Quiz')
# now do something with quizdir
and if you need an absolute directory to run a system call, subprocess functions have a cwd parameter for that. So you can avoid os.chdir 99% of the time.
I am building a python utility which automates sysadmin type tasks. Part of the tool involves writing scripts and then calling them with powershell from the python interface. An example of such code is this:
def remote_ps_session():
target = raw_input("Enter your target hostname: ")
print "Creating target.ps1 file to establish connection"
pstarget = open("pstarget.ps1", "w")
pstarget.write("$target = New-Pssession " + target + "\n")
pstarget.write("Enter-PSSession $target" + "\n")
pstarget.close()
print "File created. Initiating Connection to remote host..."
os.system("powershell -noexit -ExecutionPolicy Unrestricted " + "C:\path\to\my\file\pstarget.ps1")
I would like to do two things which I think can be answered with the same method, I've just yet to find out what is best (importing vs variables vs initial setup definitions and so on)
For simplicity we'll say the utility is in C:\utility and the powershell functions are in a functions folder one level deeper: C:\utility\functions
I want to be able to specify a location for 1) where the script (the file that is written) is saved to and then 2) refer to that location when the os.system call is made. I want this to be able to run on most/any modern Windows system.
My thoughts on possibilities are:
When the script launches get the current directory and save that as a variable, if I need to go back a directory take that variable and remove everything after the last \ and so on. Doesn't seem ideal.
On the first launch of the file prompt for system locations to put in variables. For instance have it prompt 'where do you want your log files?' 'where do you want your output files?' 'where do you want your generated scripts?' These could then be referred to as variables but would break if they ever moved folders and may not be easy to 'fix' for a user.
I imagine there is some way to refer to current directories and navigate to ..\parallel folder to where I am executing from. ....\2 folders up, but that also seems like it might be messy. I've yet to see what a standard/best practice for managing this is.
Edit: based on some comments I think __file__ might be the place to start looking. I'm going to dig in to this some but any examples (for example: __file__/subfoldernameor whatever the usage would be would be cool.
Python has a lib dedicated to path manipulation os.path, so anytime you need filesystem paths manipulation take a look at it.
As for your particular questions, run the following example, to see how you can use the functions from this lib:
test.py
import os
# These two should basicly be the same,
# but `realpath` resolves symlinks
this_file_absolute_path = os.path.abspath(__file__)
this_file_absolute_path1 = os.path.realpath(__file__)
print(this_file_absolute_path)
print(this_file_absolute_path1)
this_files_directory_absolute_path = os.path.dirname(this_file_absolute_path)
print(this_files_directory_absolute_path)
other_script_file_relative_path = "functions/some.ps"
print(other_script_file_relative_path)
other_script_file_absolute_path = os.path.join(this_files_directory_absolute_path,
other_script_file_relative_path)
print(other_script_file_absolute_path)
print("powershell -noexit -ExecutionPolicy Unrestricted %s" %
other_script_file_absolute_path)
You should get output similar to this:
/proj/test_folder/test.py
/home/user/projects/test_folder/test.py
/proj/test_folder
functions/some.ps
/proj/test_folder/functions/some.ps
powershell -noexit -ExecutionPolicy Unrestricted /proj/test_folder/functions/some.ps
I need to create a folder that I use only once, but need to have it exist until the next run. It seems like I should be using the tmp_file module in the standard library, but I'm not sure how to get the behavior that I want.
Currently, I'm doing the following to create the directory:
randName = "temp" + str(random.randint(1000, 9999))
os.makedirs(randName)
And when I want to delete the directory, I just look for a directory with "temp" in it.
This seems like a dirty hack, but I'm not sure of a better way at the moment.
Incidentally, the reason that I need the folder around is that I start a process that uses the folder with the following:
subprocess.Popen([command], shell=True).pid
and then quit my script to let the other process finish the work.
Creating the folder with a 4-digit random number is insecure, and you also need to worry about collisions with other instances of your program.
A much better way is to create the folder using tempfile.mkdtemp, which does exactly what you want (i.e. the folder is not deleted when your script exits). You would then pass the folder name to the second Popen'ed script as an argument, and it would be responsible for deleting it.
What you've suggested is dangerous. You may have race conditions if anyone else is trying to create those directories -- including other instances of your application. Also, deleting anything containing "temp" may result in deleting more than you intended. As others have mentioned, tempfile.mkdtemp is probably the safest way to go. Here is an example of what you've described, including launching a subprocess to use the new directory.
import tempfile
import shutil
import subprocess
d = tempfile.mkdtemp(prefix='tmp')
try:
subprocess.check_call(['/bin/echo', 'Directory:', d])
finally:
shutil.rmtree(d)
"I need to create a folder that I use only once, but need to have it exist until the next run."
"Incidentally, the reason that I need the folder around is that I start a process ..."
Not incidental, at all. Crucial.
It appears you have the following design pattern.
mkdir someDirectory
proc1 -o someDirectory # Write to the directory
proc2 -i someDirectory # Read from the directory
if [ %? == 0 ]
then
rm someDirectory
fi
Is that the kind of thing you'd write at the shell level?
If so, consider breaking your Python application into to several parts.
The parts that do the real work ("proc1" and "proc2")
A Shell which manages the resources and processes; essentially a Python replacement for a bash script.
A temporary file is something that lasts for a single program run.
What you need is not, therefore, a temporary file.
Also, beware of multiple users on a single machine - just deleting anything with the 'temp' pattern could be anti-social, doubly so if the directory is not located securely out of the way.
Also, remember that on some machines, the /tmp file system is rebuilt when the machine reboots.
You can also automatically register an function to completely remove the temporary directory on any exit (with or without error) by doing :
import atexit
import shutil
import tempfile
# create your temporary directory
d = tempfile.mkdtemp()
# suppress it when python will be closed
atexit.register(lambda: shutil.rmtree(d))
# do your stuff...
subprocess.Popen([command], shell=True).pid
tempfile is just fine, but to be on a safe side you'd need to safe a directory name somewhere until the next run, for example pickle it. then read it in the next run and delete directory. and you are not required to have /tmp for the root, tempfile.mkdtemp has an optional dir parameter for that. by and large, though, it won't be different from what you're doing at the moment.
The best way of creating the temporary file name is either using tempName.TemporaryFile(mode='w+b', suffix='.tmp', prifix='someRandomNumber' dir=None)
or u can use mktemp() function.
The mktemp() function will not actually create any file, but will provide a unique filename (actually does not contain PID).