V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
nyxsonsleep
V2EX  ›  问与答

Python subprocess.run 无法执行当前目录下的可执行文件

  •  
  •   nyxsonsleep · 282 天前 · 789 次点击
    这是一个创建于 282 天前的主题,其中的信息可能已经有所发展或是发生改变。
    # C:/tmp/h.bat exist.
    subprocess.run(["h.bat"],cwd=r'C:/tmp', shell=False)
    

    报错FileNotFoundError: [WinError 2] 系统找不到指定的文件。

    1. 不能使用 shell=True ,这种情况下可以执行 h.bat ,但是 review 要求不能使用。
    2. 尝试了改变 run 函数的 env 参数,但是无效。可以减少内容,但是不能改变内容。不明原因

    寻求一种方法直接可以运行 subprocess.run 函数直接执行 h.bat 的方法。

    14 条回复    2024-03-18 17:45:27 +08:00
    ysc3839
        1
    ysc3839  
       282 天前 via Android
    根据 CreateProcessW 文档的说法,是不会去参数里指定的 cwd 搜索可执行文件的,只会在当前进程的 cwd 中搜索。
    https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
    chenqh
        2
    chenqh  
       282 天前
    为什么不使用绝对路径呢?
    nyxsonsleep
        3
    nyxsonsleep  
    OP
       282 天前
    @chenqh 这里不希望使用绝对路径。而且用 shell=True 就不用绝对路径也能执行。
    而且如果改变 os.environ 的 PATH 参数,就能不在绝对路径的情况下执行了。
    这个函数的行为比较奇怪。
    nyxsonsleep
        4
    nyxsonsleep  
    OP
       282 天前
    @ysc3839 如果改变 os.environ 有效,但是改变 env 参数无效又是为什么呢?
    ysc3839
        5
    ysc3839  
       282 天前 via Android
    @nyxsonsleep 因为也只会在当前进程的 PATH 中搜索,不会去参数里指定的 PATH 搜索
    rrfeng
        6
    rrfeng  
       282 天前
    最好写一个方法获取当前路径,然后拼接成绝对路径。
    nyxsonsleep
        7
    nyxsonsleep  
    OP
       282 天前
    @ysc3839 env 参数是环境变量。env 都不搜索,那这个 env 意义是什么?
    ysc3839
        8
    ysc3839  
       282 天前 via Android
    @nyxsonsleep 我试了一下,POSIX exec 带 envp 的版本也不会在 envp 的 PATH 里搜索,所以微软只是保持了和 POSIX 行为一致,具体原因你得问 POSIX 了。
    https://man7.org/linux/man-pages/man3/exec.3p.html
    lambdaq
        9
    lambdaq  
       282 天前
    你这 cwd=r'C:/tmp' 已经改了当前目录了。 确认 C:/tmp/h.bat 存在吗?
    nyxsonsleep
        10
    nyxsonsleep  
    OP
       282 天前
    @ysc3839 但是我添加 env 参数如果是删除 PATH 中的个别字段是生效的。
    比如我在系统环境变量中添加了 C:/tmp ,可以直接
    ```
    subprocess.run(["h.bat"],cwd=r'C:/tmp', shell=False) # 可以直接执行
    ```
    但此时如果像下面这样删除环境变量中的部分字段,又无法再次搜索到 h.bat
    ```
    new_env = os.environ.copy()
    new_env["PATH"].replace('C:/tmp;','')
    subprocess.run(["h.bat"],cwd=r'C:/tmp',env=new_env)
    ```
    奇怪的是如果反过来,系统环境变量中并没有'C:/tmp',但是在 env 中添加,这个字段不会生效。
    ```
    new_env = os.environ.copy()
    new_env["PATH"]='C:/tmp;'+new_env["PATH"]
    subprocess.run(["h.bat"],cwd=r'C:/tmp',env=new_env)
    ```

    这又是什么原理?
    nyxsonsleep
        11
    nyxsonsleep  
    OP
       282 天前
    @lambdaq 这是肯定的
    lambdaq
        12
    lambdaq  
       282 天前
    note that when resolving or searching for the executable path with shell=False, cwd does not override the current working directory and env cannot override the PATH environment variable


    文档写得挺仔细。 @nyxsonsleep
    ysc3839
        13
    ysc3839  
       282 天前 via Android
    @nyxsonsleep 我自己测试了,并没有问题
    ipwx
        14
    ipwx  
       282 天前
    加一个 cmd.exe 怎么样。

    可能是 ["cmd.exe", "/C", "h.bat"]
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   993 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 21:49 · PVG 05:49 · LAX 13:49 · JFK 16:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.