与shell中的'cd'命令等效的更改工作目录的命令是什么?

845

cd 是用于改变工作目录的 shell 命令。

Python 中如何更改当前的工作目录?


2
所以在解释器中 os.chdir(os.path.join(os.path.abspath(os.path.curdir),u'subfolder')) - 或者呢? - Mr_and_Mrs_D
2
在这个上下文中很有趣:查找当前目录和文件目录os.getcwd() - Martin Thoma
15个回答

931
你可以使用以下命令更改工作目录:
import os

os.chdir(path)

你应该小心,改变目录可能会导致你的代码在新位置应用破坏性的改变。更糟糕的是,在改变目录后不要捕获诸如WindowsErrorOSError的异常,因为这可能意味着破坏性的改变被应用在的位置!

如果你使用的是Python 3.11或更新版本,那么考虑使用这个上下文管理器,以确保在完成后返回到原始的工作目录:

from contextlib import chdir

with chdir(path):
    # do stuff here

如果您使用的是较旧版本的Python,Brian M. Hunt的回答展示了如何自定义上下文管理器:他的回答
在子进程中更改当前工作目录不会改变父进程的当前工作目录。这对Python解释器也是如此。您不能使用os.chdir()来更改调用进程的当前工作目录。

5
cdunn2001 的基于装饰器的轻量级答案是现代 Python 中的理想方法。上述答案展示了其中的原因。除非您确定自己知道在做什么,否则**永远不要在上下文管理器之外调用 os.chdir()**。(你很可能不知道。) - Cecil Curry
7
这是我认为在交互式 shell 中最简单的方法。请注意,在 Windows 中,您必须使用正斜杠,例如 os.chdir("C:/path/to/location") - Josiah
1
需要注意的一件事是,如果你将Python程序制作成可执行文件并在cron中运行它,它将在你的主目录中启动。因此最好使用完全限定路径。这肯定有效,但我仍然会在任何我从Python调用的脚本中使用完全限定路径,因为不能保证这个规则适用于Python程序之外的情况。 - SDsolar
2
在Windows中,如果您复制了带有反斜杠的路径,则使用原始字符串更容易。 r'C:\path\to\location' - Burak
虽然 os.chdir 不会更改父目录,但您应该注意,在某些情况下,您可以创建一个别名,使用 cd 来模拟脚本,从而更改调用它的目录(不是在 Python 中,但您可以使用一个命令执行多个指令,包括运行 Python 脚本)。例如:alias myAlias="cd ..;./myPythonScript.py;cd ~"。由于别名不是技术上的脚本,所以它可以工作。 - Brōtsyorfuzthrāx

362
这是一个改变工作目录的上下文管理器示例。它比其他地方提到的 ActiveState version 更简单,但可以完成任务。

上下文管理器:cd

import os

class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)

或者尝试使用ContextManager,以获得更简洁的等效代码(如下)。

示例

import subprocess # just to call an arbitrary command e.g. 'ls'

# enter the directory like this:
with cd("~/Library"):
   # we are in ~/Library
   subprocess.call("ls")

# outside the context manager we are back wherever we started.

4
如果你想知道你从哪个目录切换过来,你可以在__enter__的最后加上return self。这样你就可以用with cd('foo') as cm:进行操作,并将以前的目录作为cm.savedPath访问到。 - Sam F
请注意,有些情况下返回到旧目录(保存在“savedPath”中的目录)是不可能的。例如,如果一个权限更高的进程运行一个权限较低的进程,则第二个进程继承第一个进程的工作目录,即使在这些情况下,第二个进程也无法使用自己的能力进入该工作目录。 - Kai Petzke
我收到了以下警告信息:Attribute 'savedPath' defined outside __init__ [attribute-defined-outside-init] - alper
如果我在 with cd("~/Library"): 块内部使用 return,它仍然有效吗? - alper
我猜这就是 with 块的全部意义:确保无论如何都会调用 __exit__,即使你使用了 return - Iziminza
@alper:如果这让你烦恼,那就在__init__中定义属性,比如self.savedPath = None - Iziminza

164

cd()很容易使用生成器和装饰器来编写。

from contextlib import contextmanager
import os

@contextmanager
def cd(newdir):
    prevdir = os.getcwd()
    os.chdir(os.path.expanduser(newdir))
    try:
        yield
    finally:
        os.chdir(prevdir)

然后,即使抛出异常,目录也会被还原:

os.chdir('/home')

with cd('/tmp'):
    # ...
    raise Exception("There's no place like /home.")
# Directory is now back to '/home'.

3
请注意可能的失误(忘记使用try/finally)。 - cdunn2001
8
太棒了!如果从被接受的答案的介绍性评论中提取内容注入到这个答案中,那将会无比理想。不过,这个答案用Python编写非常简洁和安全,我要全部点赞。 - Cecil Curry
3
为什么使用 yield 而不是 return?这是否应该是一个生成器? - EKons
2
@NicoBerrogorry,这是一个生成器。请参阅contextlib.contextmanager中的文档。这在Python中是非常有用的模式,值得学习。 - cdunn2001
1
你不应该在 try 块中使用 chdir 吗? - Rainbow Fossil
显示剩余6条评论

153

我会像这样使用 os.chdir

os.chdir("/path/to/change/to")

顺便提一句,如果你需要找出当前路径,可以使用 os.getcwd()

更多内容请点击这里


27

如果您正在使用相对较新的Python版本,您也可以使用上下文管理器,例如这个

from __future__ import with_statement
from grizzled.os import working_directory

with working_directory(path_to_directory):
    # code in here occurs within the directory

# code here is in the original directory

更新

如果你更喜欢自己动手:

import os
from contextlib import contextmanager

@contextmanager
def working_directory(directory):
    owd = os.getcwd()
    try:
        os.chdir(directory)
        yield directory
    finally:
        os.chdir(owd)

1
不错的通用想法。这里有一个Activestate recipe,没有其他依赖项。 - cfi
4
依赖性不好。Python内置的contextlib.contextmanager装饰器很好用。可以参考cdunn2001基于装饰器的答案,该答案现在应该是最佳答案。 - Cecil Curry

16

正如其他人指出的那样,上面所有的解决方案都只会改变当前进程的工作目录。当您回到Unix shell时,这将会丢失。如果非常需要,您可以使用这个可怕的黑客方法更改Unix上的父shell目录:

def quote_against_shell_expansion(s):
    import pipes
    return pipes.quote(s)

def put_text_back_into_terminal_input_buffer(text):
    # use of this means that it only works in an interactive session
    # (and if the user types while it runs they could insert characters between the characters in 'text'!)
    import fcntl, termios
    for c in text:
        fcntl.ioctl(1, termios.TIOCSTI, c)

def change_parent_process_directory(dest):
    # the horror
    put_text_back_into_terminal_input_buffer("cd "+quote_against_shell_expansion(dest)+"\n")

7
疯狂、脆弱的黑客获取了强制投票。任何人都不应该这样做,特别是带有“如果用户在运行时键入...”警告的情况下。尽管如此,在我身上,它仍然激起了叛逆胡子的兴奋点,因为改变父目录CWD有点但又不完全可行。所有人都应该得到投票! - Cecil Curry
这就是我一直在寻找的解决方案,感谢您的技巧。我不确定是否会坚持使用它,还是像使用Python脚本更改shell中的工作目录建议的那样使用shell函数。我还提到了您的解决方案,并对Python 3进行了一些修改,详见此答案 - David Heresy

12

os.chdir() 是 Python 中的 cd 命令。


12

os.chdir() 是正确的方式。


11
import os

abs_path = 'C://a/b/c'
rel_path = './folder'

os.chdir(abs_path)
os.chdir(rel_path)
你可以使用os.chdir(abs_path)或os.chdir(rel_path)两者都可以,不需要调用os.getcwd()来使用相对路径。

1
运行良好。可以使用os.getcwd()来验证在更改目录之前和之后的当前目录。 - vinsinraw

6
更进一步,根据Brian指出的方向,并基于sh(1.0.8+)的链接
from sh import cd, ls

cd('/tmp')
print ls()

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