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

时间:2022-02-14 20:12:04

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:

我正在尝试实现我自己版本的'cd'命令,该命令向用户显示可供选择的硬编码目录列表,并且用户必须输入与列表中的条目对应的数字。这个名为my_cd.py的程序现在应该有效地“cd”用户到所选目录。这应该如何工作的示例:

/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:

目前,我正在尝试使用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

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?

关于如何让它发挥作用的任何想法?是否可以从python脚本更改我的交互式shell的当前目录?

5 个解决方案

#1


2  

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.

这是不可能做到的。父进程看不到对工作目录的更改。最多可以让Python脚本打印要更改的目录,然后让源脚本实际更改为该目录。

#2


7  

Change your sourced bash code to:

将您的来源bash代码更改为:

#! /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.

和你的Python代码在sys.stderr上做所有的化妆品输出(消息给用户,菜单等),最后,而不是os.chdir,只需打印(到sys.stdout)的路径目录应该改变。

#3


3  

my_cd.py:

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


2  

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

它的价值,因为这个问题也标记为“bash”,这里是一个简单的bash-only解决方案:

$ 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:

现在,这个脚本必须是source'd,而不是执行:

$ 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.

要解决您的情况,您可以让用户运行的命令是一个别名,该别名来源bash脚本,它首先执行dir选择,然后在cd完成后潜入python程序。

#5


1  

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

与上述内容相反,您可以通过更换过程图像两次来完成此操作。

In bash, replace your my_cd function with:

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

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

Then your python script has to finish with:

然后你的python脚本必须完成:

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

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

记得在脚本的开头导入os,sys。

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).

但请注意,这是边缘黑客攻击。你的shell死了,用python脚本替换它,在同一个进程中运行。 python脚本对环境进行了更改,并将shell替换为自身,然后又在同一个进程中。这意味着如果您在上一个shell会话中有其他本地未保存和未导出的数据或环境,则它将不会持久保存到新的。这也意味着rc和profile脚本将再次运行(通常不是问题)。

#1


2  

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.

这是不可能做到的。父进程看不到对工作目录的更改。最多可以让Python脚本打印要更改的目录,然后让源脚本实际更改为该目录。

#2


7  

Change your sourced bash code to:

将您的来源bash代码更改为:

#! /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.

和你的Python代码在sys.stderr上做所有的化妆品输出(消息给用户,菜单等),最后,而不是os.chdir,只需打印(到sys.stdout)的路径目录应该改变。

#3


3  

my_cd.py:

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


2  

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

它的价值,因为这个问题也标记为“bash”,这里是一个简单的bash-only解决方案:

$ 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:

现在,这个脚本必须是source'd,而不是执行:

$ 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.

要解决您的情况,您可以让用户运行的命令是一个别名,该别名来源bash脚本,它首先执行dir选择,然后在cd完成后潜入python程序。

#5


1  

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

与上述内容相反,您可以通过更换过程图像两次来完成此操作。

In bash, replace your my_cd function with:

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

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

Then your python script has to finish with:

然后你的python脚本必须完成:

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

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

记得在脚本的开头导入os,sys。

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).

但请注意,这是边缘黑客攻击。你的shell死了,用python脚本替换它,在同一个进程中运行。 python脚本对环境进行了更改,并将shell替换为自身,然后又在同一个进程中。这意味着如果您在上一个shell会话中有其他本地未保存和未导出的数据或环境,则它将不会持久保存到新的。这也意味着rc和profile脚本将再次运行(通常不是问题)。