我需要更改 Python 应用程序调用的程序。不幸的是,我无法更改 Python 代码。我只能更改调用环境(特别是 PATH
)。但不幸的是,Python 的子进程模块似乎忽略了 PATH
(至少在某些情况下)。
在搜索要调用的二进制文件时,如何强制 Python 遵循 PATH
?
为了说明问题,这里有一个 MVCE。实际的 Python 应用程序正在使用 subprocess.check_output(['nvidia-smi', '-L'])
,但以下简化代码显示了相同的行为。
创建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
在我的系统1 上打印:
./whoami
foobar
konrad
konrad
我期望这段代码总是打印foobar
而不是konrad
。
我的 MVCE 包含 os.execvp
调用,因为 the subprocess
documentation指出
On POSIX, the class uses
os.execvp()
-like behavior to execute the child program.
不用说,实际 execvp
POSIX API,从 C 调用,确实尊重PATH
,所以这是一个特定于 Python 的问题。
1 Ubuntu 18.04.2 LTS,Python 3.6.9。
最佳答案
根据我的评论,这是由于 Python 对 execvp
的实现所致不符合 POSIX execvp
语义。特别是 Python doesn't respond to ENOEXEC
errors通过将文件解释为 shell 脚本并需要一个显式的 shebang。
将文件创建为:
printf '#!/bin/sh\necho foobar\n' > ./whoami
使事情按预期工作
请注意,这已经有一段时间了:https://bugs.python.org/issue19948
关于python - 为什么子进程忽略 PATH,我该如何更改它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62893701/