То, что shebang использовать для скриптов python, выполняется под pyenv virtualenv

Когда предполагается, что python script запускается из pyenv virtualenv, что является правильным shebang для файла?

В качестве примера тестового примера, в python по умолчанию для моей системы (OSX) не установлен pandas. Pyenv virtualenv venv_name делает. Я попытался получить путь к исполняемому файлу python из virtualenv.

$ pyenv activate venv_name
(venv_name)$ which python
/Users/username/.pyenv/shims/python


Поэтому я сделал свой пример script.py:

#!/Users/username/.pyenv/shims/python
import pandas as pd
print 'success'


Но когда я попытался запустить script, я получил сообщение об ошибке:

(venv_name) $ ./script.py
./script.py: line 2: import: command not found
./script.py: line 3: print: command not found


Хотя запуск этого пути в командной строке работает нормально:

(venv_name) $ /Users/username/.pyenv/shims/python script.py
success

(venv_name) $ python script.py # also works
success

Что для этого нужно? В идеале, я хочу что-то общее, чтобы оно указывало на питон любого моего текущего venv.

Ответ 1

Я действительно не знаю, почему вызов интерпретатора с полным путем не сработает для вас, я использую его все время, но если вы хотите использовать интерпретатор python, который находится в вашей среде, вы должны сделать:

#!/usr/bin/env python

Таким образом вы выполняете поиск в среде, в которой используется интерпретатор python.

Ответ 2

Если вам нужно использовать больше оболочки, чем вы можете поместить в строку #! shebang, вы можете запустить файл с помощью простой оболочки script, которая запускает Python в том же файле.

#!/bin/bash
"exec" "pyenv" "exec" "python" "$0" "[email protected]"
# the rest of your Python script can be written below

Из-за цитирования Python не выполняет первую строку и вместо этого объединяет строки для модуля docstring... который фактически игнорирует его.

Здесь вы можете увидеть .

Ответ 3

Как вы и ожидали, вы должны иметь возможность использовать полный путь к виртуальной среде python в shebang для выбора/управления средой, в которой работает script, независимо от среды управления script.

В комментариях к вашему вопросу VPfB вы обнаружите, что /Users/username/.pyenv/shims/python представляет собой оболочку script, которая выполняет exec $pyenv_python. Вы должны иметь возможность echo $pyenv_python определить реальный питон и использовать его в качестве своего сибанга.

Смотрите также: https://unix.stackexchange.com/questions/209646/how-to-activate-virtualenv-when-a-python-script-starts

Попробуйте pyenv virtualenvs найти список каталогов виртуальной среды.

И тогда вы можете найти использование shebang примерно так:

#!/Users/username/.pyenv/python/versions/venv_name/bin/python
import pandas as pd
print 'success'

... позволит script работать с использованием выбранной виртуальной среды в других (виртуальных или нет) средах:

(venv_name) $ ./script.py 
success
(venv_name) $ pyenv activate non_pandas_venv 
(non_pandas_venv) $ ./script.py
success
(non_pandas_venv) $ . deactivate
$ ./script.py
success
$

Трюк заключается в том, что если вы вызываете двоичную информацию виртуальной среды python, python просматривает это место двоичного пути для поддерживающих файлов и заканчивает работу с использованием окружающей виртуальной среды. (См. Per Как работает virtualenv?)

Ответ 4

может быть, вам нужно проверить права доступа к файлу:

sudo chmod +x script.py

Ответ 5

Это не совсем ответ на вопрос, но это предложение от ephiement, я думаю, гораздо лучший способ сделать то, что вы хотите. Я немного развил и добавил еще несколько объяснений о том, как это работает и как вы можете динамически выбирать питон для использования:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $ALTERNATIVE_PYTHON
    exec $PREFERRED_PYTHON "$0" "[email protected]"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "[email protected]"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "[email protected]"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())