How do I change my current directory from a python script?

限于喜欢 提交于 2019-12-05 02:23:29

问题


I'm trying to implement my own version of the 'cd' command that presents the user with a list of hard-coded directories to choose from, and the user has to enter a number corresponding to an entry in the list. The program, named my_cd.py for now, should then effectively 'cd' the user to the chosen directory. Example of how this should work:

/some/directory
$ my_cd.py
1) ~
2) /bin/
3) /usr
Enter menu selection, or q to quit: 2

/bin
$

Currently, I'm trying to 'cd' using os.chdir('dir'). However, this doesn't work, probably because my_cd.py is kicked off in its own child process. I tried wrapping the call to my_cd.py in a sourced bash script named my_cd.sh:

#! /bin/bash
function my_cd() {
    /path/to/my_cd.py
}

/some/directory
$ . my_cd.sh
$ my_cd
... shows list of dirs, but doesn't 'cd' in the interactive shell

Any ideas on how I can get this to work? Is it possible to change my interactive shell's current directory from a python script?


回答1:


This can't be done. Changes to the working directory are not visible to parent processes. At best you could have the Python script print the directory to change to, then have the sourced script actually change to that directory.




回答2:


Change your sourced bash code to:

#! /bin/bash
function my_cd() {
    cd `/path/to/my_cd.py`
}

and your Python code to do all of its cosmetic output (messages to the users, menus, etc) on sys.stderr, and, at the end, instead of os.chdir, just print (to sys.stdout) the path to which the directory should be changed.




回答3:


my_cd.py:

#!/usr/bin/env python
import sys

dirs = ['/usr/bin', '/bin', '~']
for n, dir in enumerate(dirs):
    sys.stderr.write('%d) %s\n' % (n+1, dir))
sys.stderr.write('Choice: ')
n = int(raw_input())
print dirs[n-1]

Usage:

nosklo:/tmp$ alias mcd="cd \$(/path/to/my_cd.py)"
nosklo:/tmp$ mcd
1) /usr/bin
2) /bin
3) ~
Choice: 1
nosklo:/usr/bin$ 



回答4:


For what its worth, since this question is also tagged "bash", here is a simple bash-only solution:

$ cat select_cd
#!/bin/bash

PS3="Number: "

dir_choices="/home/klittle /local_home/oracle"

select CHOICE in $dir_choices; do
   break
done

[[ "$CHOICE" != "" ]] &&  eval 'cd '$CHOICE

Now, this script must be source'd, not executed:

$ pwd
/home/klittle/bin
$ source select_cd
1) /home/klittle
2) /local_home/oracle
Number: 2
$ pwd
/local_home/oracle

So,

$ alias mycd='source /home/klittle/bin/select_cd'
$ mycd
1) /home/klittle
2) /local_home/oracle
Number:

To solve your case, you could have the command the user runs be an alias that sources a bash script, which does the dir selection first, then dives into a python program after the cd has been done.




回答5:


Contrary to what was said, you can do this by replacing the process image, twice.

In bash, replace your my_cd function with:

function my_cd() {
    exec /path/to/my_cd.py "$BASH" "$0"
}

Then your python script has to finish with:

os.execl(sys.argv[1], sys.argv[2])

Remember to import os, sys at the beginning of the script.

But note that this is borderline hack. Your shell dies, replacing itself with the python script, running in the same process. The python script makes changes to the environment and replaces itself with the shell, back again, still in the same process. This means that if you have some other local unsaved and unexported data or environment in the previous shell session, it will not persist to the new one. It also means that rc and profile scripts will run again (not usually a problem).



来源:https://stackoverflow.com/questions/2571524/how-do-i-change-my-current-directory-from-a-python-script

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!