Почему подпроцесс игнорирует PATH и как это изменить? - PullRequest
2 голосов
/ 14 июля 2020

Мне нужно изменить программу, вызываемую приложением 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

I ожидайте этот код всегда будет печатать foobar вместо konrad.

Мой MVCE включает вызов os.execvp, потому что документация subprocess утверждает, что

В POSIX класс использует os.execvp() -подобное поведение для выполнения дочерней программы.

Излишне говорить, что фактический execvp API POSIX, вызываемый из C, уважает PATH, так что это проблема Python специфическая c.

1 Ubuntu 18.04.2 LTS, Python 3.6.9.

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Ваш

echo 'echo foobar' >whoami
chmod +x whoami

работает некорректно.

Python не выбирает его как исполняемый файл, хотя бит выполнения установлен, он не знает об этом сначала нужно запустить bash, чтобы выполнить, таким образом, он пропускает путь и запускает исходный whoami, который пропатчен / usr / bin / whoami

добавление shebang

echo "#!/bin/sh" > whoami
echo 'echo foobar' >> whoami
chmod +x whoami

On В системах стиля Unix (включая Linux / OS X) строка shebang, как она называется, сообщает загрузчику (или ядру, или иногда оболочке), какую программу использовать для запуска файла. В самом начале c вы должны указать путь к интерпретатору python.

Я подозреваю, что если вы ./whoami (с установленным разрешением на выполнение), оболочка делает некоторые дополнительные действия c поэтому вам не нужно вводить / bin / sh $ PWD / whoami

, если вы выполняете

chmod -x whoami

, вы можете использовать специальный

. ./whoami (указать оболочке выполнить его как сценарий оболочки).

обратите внимание, что execvp должен использовать / bin / sh, а не bash. также . ./whoami будет зависеть от того, какую оболочку вы используете, большинство из них будет "исходным" файлом, а не запускать его в другом процессе (т.е. изменения в среде, рабочем каталоге и т. д. c останутся)

Если нет заголовка shebang или исполняемого файла, оболочка просто использует себя в качестве интерпретатора по умолчанию (но только при вызове через ./whoami;. ./Whoami отличается, она создает файл, независимо от того, является ли он исполняемым).

Запутанная природа execvp (POSIX, а не Python), по-видимому, также делает это. Python в этом случае не работает, потому что os.execvp фактически не вызывает execvp изнутри, его сходство только в названии.

1 голос
/ 14 июля 2020

согласно моему комментарию, это связано с тем, что реализация Python execvp не соответствует семантике POSIX execvp. в частности, Python не отвечает на ENOEXEC ошибки , интерпретируя файл как сценарий оболочки и требует явного shebang.

создание файла как:

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

заставляет все работать должным образом

обратите внимание, что об этом уже давно известно: https://bugs.python.org/issue19948

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...