【问题标题】:what shebang to use for python scripts run under a pyenv virtualenv用于 python 脚本的 shebang 在 pyenv virtualenv 下运行
【发布时间】:2017-10-19 23:35:08
【问题描述】:

当 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'


但是当我尝试运行脚本时,我得到了一个错误:

(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?理想情况下,我想要一些通用的东西,以便它指向我当前 venv 的 python。

【问题讨论】:

  • 我经常使用它,而且效果很好。我的 shebang 的一个例子很好用:#!/home/dslima90/.virtualenvs/production_enviroment/bin/python,也许检查你的路径?你不是想念 bin 吗?
  • 对不起,我的 devel 文件夹中有我的 python 解释器的别名,这就是为什么我的工作(在开发中)......无论如何#!/usr/bin/env python 应该为你做......你可以试试命令行之前。看看它是否调用了正确的解释器。
  • 你可以用od -c script.py检查#!是否真的是前两个字符。
  • @xgord 因此排除了一种可能的原因。这也可能值得检查:stackoverflow.com/questions/9988125/… .../shims/python 是另一个脚本吗?
  • @VPfB 哇,是的,你是对的。事实证明,它只是一个在最后调用... exec $pyenv_python 的bash 脚本。该文件由pyenv 创建,我只是假设它会复制或链接python 可执行文件,但事实并非如此。谜团解开了!

标签: python python-2.7 pyenv


【解决方案1】:

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

#!/usr/bin/env python

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

【讨论】:

  • 确认它在 2018 年 4 月仍然适用于 Python 3.6.4,谢谢!
  • 感谢 python 的“virtual shebangs”功能,这甚至可以在 Windows 上运行。
  • 不幸的是,这种方法现在与 Debian Python 包策略冲突,后者已弃用此方法,而支持显式 /usr/bin/python3 shebang。 pyenv 可以正确处理吗?
  • @davidA 似乎这本身就是一个很好的 SO 问题,对于为 debian pkgs 的代码寻找一个好的解决方案的人来说。但是这个特定问题对于我最初问题的用例并不重要,因为它只是一个用户脚本,并且仍然适用于当前版本的 python。 (最初的问题也是从过去的时代回来的,当时 python 2 仍然是一个东西,但不确定这在事物的元中是否重要)
  • 我在 Windows 上为跨平台编写代码。在 Linux 上,使用 env 命令时出现错误:/usr/bin/env: 'python\r': No such file or directory - 所以我必须在 Windows 上的 python 文件中更改为换行符表示,它工作正常。
【解决方案2】:

如您所料,无论控制脚本的环境如何,您都应该能够在 shebang 中使用虚拟环境的 python 的完整路径来选择/控制脚本运行的环境。

在关于您的问题的 cmets 中,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 查找虚拟环境目录列表。

然后你可能会发现一个 using 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?

【讨论】:

  • 知道如何找到 virtualenv 的 python 的实际路径很方便,尽管这个解决方案缺少其他 2 个答案处理的部分:即能够从任何当前活动的 virtualenv 执行脚本。看起来使用这种方法,您需要提前知道它将使用哪个 virtualenv 执行,并且只能通过那个 virtualenv 执行它。
  • 我在尝试运行依赖于特定虚拟环境中包的脚本时发现了这个问题,同时处于不同的环境中。特别是,我在命令行中进行了开发,但我需要从 cron 作业中运行脚本。通过直接在shebang中调用虚拟环境的python,我不需要先设置一个匹配的虚拟环境shell,然后调用该环境的默认python。它根本不需要在父进程中激活任何virtualenv。
  • 啊,我现在在您的问题中看到您想要通用的 shebang,而不是通常成功执行特定的 virtualenv 相关脚本。
【解决方案3】:

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

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

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

你可以看到更多here

【讨论】:

  • @ephemient - 这太棒了 - 我在下面详细阐述了你的建议;希望没问题
【解决方案4】:

它并没有完全回答问题,但我认为 ephiement 的这个建议是做你想做的更好的方法。我已经详细说明并添加了一些关于它如何工作以及如何动态选择要使用的 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 "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

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

【讨论】:

    【解决方案5】:

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

    #!/usr/bin/env python
    

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

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

    基本上,您可以在终端上调用 python 是您在#! 之后放置的内容。

    【讨论】:

      【解决方案6】:

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

      sudo chmod +x script.py
      

      【讨论】:

      • 问题下方的 cmets 解释了为什么它不起作用。但我的示例也表明必须设置执行位,因为 ./script.py 的输出是 not permission denied,如果未设置执行位。
      猜你喜欢
      • 2021-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多