在 pyenv virtualenv 下 python 脚本 运行 使用什么 shebang

what shebang to use for python scripts run under a pyenv virtualenv

当 python 脚本应该是 运行 来自 pyenv virtualenv 文件的正确 shebang 是什么?

作为示例测试用例,我的系统 (OSX) 上的默认 python 没有安装 pandas。 pyenv virtualenv venv_name 可以。我尝试从 virtualenv.

获取 python 可执行文件的路径
$ 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'


但是当我尝试 运行ning 脚本时,出现错误:

(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

什么是合适的 shebang?理想情况下,我想要一些通用的东西,以便它指向 python 我当前的 venv 是什么。

我真的不知道为什么用完整路径调用解释器对你不起作用,我一直使用它,但如果你想使用你的 python 解释器你应该做的环境:

#!/usr/bin/env python

这样您就可以在环境中搜索要使用的 python 解释器。

如果您需要使用的 shell 超出 #! shebang 行,您可以使用一个简单的 shell 脚本启动该文件,该脚本会启动 Python 在同一个文件上。

#!/bin/bash
"exec" "pyenv" "exec" "python" "[=10=]" "$@"
# the rest of your Python script can be written below

由于引用,Python 不执行第一行,而是将字符串连接在一起作为模块文档字符串...这实际上忽略了它。

你可以看到更多here

如您所料,您应该能够在 shebang 中使用虚拟环境 python 的完整路径到 choose/control 脚本运行的环境,而不管控制脚本的环境如何.

在您的问题的评论中,VPfB 和您发现 /Users/username/.pyenv/shims/python 是执行 exec $pyenv_python 的 shell 脚本。您应该能够 echo $pyenv_python 确定真正的 python 并将其用作您的 shebang。

另请参阅: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'

... 将使脚本能够在其他(虚拟或非虚拟)环境中使用所选的虚拟环境:

(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 会在该二进制文件的路径位置周围查找支持文件,并最终使用周围的虚拟环境。 (参见 How does virtualenv work?

也许您需要检查文件权限:

sudo chmod +x script.py

这并不能完全回答问题,但我认为 ephiement 的这个建议是做你想做的事情的更好方法。我已经详细阐述了一些,并添加了更多关于它如何工作以及如何动态地 select 使用 python 的解释:

#!/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 "[=10=]" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "[=10=]" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "[=10=]" "$@"
fi
exit 127
'''

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

要扩展到这个答案,在 99% 的情况下是的,如果您的环境中有 python,您可以只使用:

#!/usr/bin/env python

但是对于 linux 上的自定义 venv,遵循相同的语法对我不起作用,因为 venv 创建了一个 link 到 python创建 venv 的解释器,所以我必须执行以下操作:

#!/path/to/the/venv/bin/python

基本上你可以在你的终端上调用 python 是你在 #!.

之后的内容

如果你只想要一个简单的 pyenv virtualenv 脚本选择,你可以使用一个 bash 脚本,你的源 'here document' 如下:

#!/bin/bash
PYENV_VERSION=<your_pyenv_virtualenv_name> python - $@ <<EOF
import sys
print(sys.argv)
exit
EOF

我做了一些额外的测试。以下也适用:

#!/usr/bin/env -S PYENV_VERSION=<virtual_env_name> python