如何为子进程指定工作目录

246
有没有一种方法可以在Python的subprocess.Popen()中指定命令的运行目录?
例如:
Popen('c:\mytool\tool.exe', workingdir='d:\test\local')

我的Python脚本位于C:\programs\python

是否可以在目录D:\test\local中运行C:\mytool\tool.exe

如何为子进程设置工作目录?


3
请记住,subprocess.call 只是 subprocess.Popen 的一个简单封装,这个封装将处理所有与 Popen 相关的参数,至少根据我的记忆是这样的 :) 在简单的情况下,最好使用 subprocess.call。 - shabunc
现在你应该更倾向于使用subprocess.run,虽然call和稍微新一点的遗留包装器check_callcheck_output仍然可用。 - tripleee
2个回答

361

subprocess.Popen 需要一个cwd参数 来设置当前工作目录;你还需要转义你的反斜杠 ('d:\\test\\local'),或使用 r'd:\test\local' 以避免Python将反斜杠解释为转义字符。以现在这种写法,\t 部分会被翻译成一个 制表符

所以,你的新代码行应该是:

subprocess.Popen(r'c:\mytool\tool.exe', cwd=r'd:\test\local')

要将您的Python脚本路径用作cwd,请import os并使用以下方式定义cwd:

os.path.dirname(os.path.realpath(__file__)) 

3
如果将Shell=True添加到参数中,会对同时设置cwd产生什么影响? - T. Stone
3
对于独立的可执行文件,它不应该改变任何东西,除非可执行文件依赖于shell中的某些环境变量。但是,如果使用shell=False,就无法使用shell内置命令,比如cd。例如,在Linux上用两种方式都尝试这样做:subprocess.Popen("cd /tmp; pwd") - Mark Rushakoff
17
至少在Python 3中,即使在Windows机器上,您也不必使用反斜杠。只需执行以下操作:subprocess.call(["C:/Users/Bob/Some.exe"], cwd="C:/Users/Jane/"),它可以正常工作。 - mgrandi
9
工作目录必须是绝对路径吗? - DXsmiley
13
它也适用于 subprocess.check_output()。谢谢! - Samuel Dauzon
显示剩余4条评论

12

另一种简单的方法是这样:

cwd = os.getcwd()
os.chdir('c:\some\directory')
subprocess.Popen('tool.exe')
os.chdir(cwd)

如果您想依赖相对路径,例如,如果您的工具位于c:\some\directory\tool.exe,则此解决方案适用。对于Popencwd关键字参数将不允许您这样做。一些脚本/工具可能会依赖于在调用它们时处于给定目录中。为了使代码更简洁,即从“业务逻辑”中分离与更改目录相关的逻辑,您可以使用装饰器。

def invoke_at(path: str):
    def parameterized(func):
        def wrapper(*args, **kwargs):
            cwd = os.getcwd()
            os.chdir(path)

            try:
                ret = func(*args, **kwargs)
            finally:
                os.chdir(cwd)

            return ret

        return wrapper

    return parameterized            

这样的装饰器可以这样使用:

@invoke_at(r'c:\some\directory')
def start_the_tool():
    subprocess.Popen('tool.exe')

请注意,您可以通过首先解析路径来避免相对路径问题,例如使用 Path("../../something").resolve()。尽管如此,在编写可能在 bash 中编写的快速脚本时,我经常使用 chdir - 2e0byo
@2e0byo 我必须承认,作为一名主要的Windows开发人员,我更喜欢Python而不是批处理 :) Bash对我来说不是一个选择。 - ashrasmun
1
实际上这是我找到的唯一一种(或更好的说法:变通的)在使用Popen时“设置”工作目录的方法。谢谢。 - anion

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