如何从Python脚本中更改当前目录?

3
我正在尝试实现自己的版本的“cd”命令,它会向用户展示一些硬编码的目录供其选择,用户需要输入与列表中条目对应的数字。该程序暂时命名为my_cd.py,然后有效地将用户“cd”到所选目录。以下是此操作的示例:
/some/directory
$ my_cd.py
1) ~
2) /bin/
3) /usr
Enter menu selection, or q to quit: 2

/bin
$

目前,我正在尝试使用 os.chdir('dir') 进行“cd”。但是,这并不起作用,可能是因为 my_cd.py 在其自己的子进程中启动。我尝试在一个名为 my_cd.sh 的源bash脚本中包装对 my_cd.py 的调用:
#! /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

有什么想法可以让这个工作吗?从Python脚本中改变我的交互式shell的当前目录是否可能?
5个回答

7

将您的源bash代码更改为:

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

请将您的Python代码编写为在sys.stderr上进行所有的美化输出(向用户发送消息,菜单等),并在最后,而不是使用os.chdir,只需将变更目录的路径打印(输出到sys.stdout)即可。


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]

使用方法:

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

如果您使用单引号,则无需转义美元符号:alias mcd='cd $(/path/to/my_cd.py)' - Dennis Williamson

2

顺便提一下,既然这个问题也标记了“bash”,这里有一个纯bash的简单解决方案:

$ 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

现在,这个脚本必须被源码引入,而不是执行它:
$ pwd
/home/klittle/bin
$ source select_cd
1) /home/klittle
2) /local_home/oracle
Number: 2
$ pwd
/local_home/oracle

那么,

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

为了解决你的问题,可以让用户运行的命令成为一个别名,该别名会先执行一个bash脚本来进行目录选择,然后在cd完成后进入python程序。

2

这是不可能的。更改工作目录对父进程不可见。最好的方法是让Python脚本打印要更改的目录,然后让源脚本实际更改到该目录。


1

与之前所说的相反,你可以通过两次替换进程映像来实现这一点。

在bash中,将你的my_cd函数替换为:

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

然后你的Python脚本必须以以下方式结束:

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

记得在脚本开头处import os, sys

但请注意,这是边缘黑客行为。你的 shell 会死掉,用 python 脚本替换自己,在同一个进程中运行。Python 脚本会更改环境并用 shell 替换自己,再次回到同一个进程中。这意味着如果你在之前的 shell 会话中有一些其他本地未保存和未导出的数据或环境,它将不会持续到新的会话中。这也意味着 rc 和 profile 脚本将再次运行(通常不是问题)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接