为什么子进程忽略 PATH,我该如何更改它?

2024-01-05

我需要更改 Python 应用程序调用的程序。很遗憾我无法更改 Python 代码。我只能改变调用环境(特别是,PATH)。但不幸的是Python的子进程模块似乎忽略了PATH(至少在某些情况下)。

我怎样才能强迫Python尊重PATH当搜索要调用哪个二进制文件时?

为了说明这个问题,这里有一个 MVCE。实际的Python应用程序正在使用subprocess.check_output(['nvidia-smi', '-L']),但以下简化代码显示了相同的行为。

Create test.py:

import os
from subprocess import run

run(['which', 'whoami'])
run(['/usr/bin/env', 'whoami'])
run(['whoami'])

os.execvp('whoami', ['whoami'])

现在创建一个本地whoami编写脚本并执行test.py:

echo 'echo foobar' >whoami
chmod +x whoami
PATH=.:$PATH python3 test.py

On my system1 this prints:

./whoami
foobar
konrad
konrad

I expect此代码始终打印foobar代替konrad.

我的 MVCE 包括os.execvp打电话因为the subprocess文档 https://docs.python.org/3/library/subprocess.html#subprocess.Popen指出

在 POSIX 上,该类使用os.execvp()-类似的行为来执行子程序。

不用说,actual execvpPOSIX API,从 C 调用,does尊重PATH,所以这是一个 Python 特定问题。


1 Ubuntu 18.04.2 LTS, Python 3.6.9.


根据我的评论,这是由于Python的实现execvp https://docs.python.org/3/library/os.html#os.execvp与 POSIX 不一致execvp https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html语义。特别是Python没有回应ENOEXEC errors https://github.com/python/cpython/blob/4f28f75deefc6e8f65694f96f1a40b0a26fc385d/Lib/os.py#L587通过将文件解释为 shell 脚本并且需要显式的 shebang。

将文件创建为:

printf '#!/bin/sh\necho foobar\n' > ./whoami

使事情按预期进行

请注意,人们已经知道这一点有一段时间了:https://bugs.python.org/issue19948 https://bugs.python.org/issue19948

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么子进程忽略 PATH,我该如何更改它? 的相关文章

随机推荐