【问题标题】:OSX: using bash to find python is different than using /usr/bin/env pythonOSX:使用 bash 查找 python 与使用 /usr/bin/env python 不同
【发布时间】:2016-04-24 00:02:41
【问题描述】:

我不知道该怎么做。如果我让我的 shell (bash) 启动 python 而不给它一个确切的路径,它会以某种方式启动错误的程序(或者可能是正确的程序,但加载了错误的 dylibs)。然而,which python/usr/bin/env python 的输出看起来都很好。

这是我在说什么的插图:

好的,首先,我的python 命令来自哪里?让我们按照符号链接。 (顺便说一句,太糟糕了 readlink -frealpath 在 OSX 上不存在......)

$ which python
/usr/local/bin/python
$ ls -l /usr/local/bin/python
lrwxr-xr-x  1 root  wheel  68 Jan 18 11:44 /usr/local/bin/python@ -> ../../../Library/Frameworks/Python.framework/Versions/2.7/bin/python
$ ls -l /Library/Frameworks/Python.framework/Versions/2.7/bin/python
lrwxr-xr-x  1 root  admin  7 Jan 18 11:44 /Library/Frameworks/Python.framework/Versions/2.7/bin/python@ -> python2
$ ls -l /Library/Frameworks/Python.framework/Versions/2.7/bin/python2
lrwxr-xr-x  1 root  admin  9 Jan 18 11:44 /Library/Frameworks/Python.framework/Versions/2.7/bin/python2@ -> python2.7
$ ls -l /Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
-rwxrwxr-x  1 root  admin  25624 Dec  5 15:57 /Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7*

如果我打电话给/usr/local/bin/pythonpython 本身认为它在哪里?它是什么版本?

$ /usr/local/bin/python -c "import sys; print sys.executable; print sys.version_info"
/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
sys.version_info(major=2, minor=7, micro=11, releaselevel='final', serial=0)

好的,看起来合法。如果我让/usr/bin/env 为我定位python,而不是输入/usr/local/bin/python,会怎样?

$ /usr/bin/env python -c "import sys; print sys.executable; print sys.version_info"
/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
sys.version_info(major=2, minor=7, micro=11, releaselevel='final', serial=0)

同样的事情。到目前为止没有任何惊喜。好的,如果我只输入python 会怎样?那应该和/usr/bin/env python一样吧?

$ python -c "import sys; print sys.executable; print sys.version_info"
/usr/local/bin/python
sys.version_info(major=2, minor=7, micro=10, releaselevel='final', serial=0)

等等,什么? sys.executable 指向符号链接,版本错误。怎么回事?

为什么输入python 与输入/usr/local/bin/python 有任何不同?

顺便说一句:

  • 我仔细检查了我的 bash 别名,python 不是其中之一。 (alias | grep python)

【问题讨论】:

    标签: python macos bash


    【解决方案1】:

    当您从 $PATH 运行程序时(所以,就像 $ python )然后它的 argv[0] 设置为它的名称(例如 python ),而不是完整路径。如果argv[0]在开始时没有反斜杠,则sys.executablelooks at $PATH的python 2.7版本(例如,当您像上一个示例一样运行它时)。而且它似乎没有解析符号链接,只是打印第一个找到的路径。

    我们可以看到in python's code,在 OS X 上,它在$PATH 中使用NSGetExecutablePath。在Apple's site 他们说NSGetExecutablePath

    也就是说,路径可能是符号链接,而不是真正的文件。

    【讨论】:

    • 感谢您的浏览。我认为你在正确的轨道上。正如tripleee 的回答所指出的,我需要运行hash -r python 来重新配置shell 的python 路径。 (我刚刚安装了一个新版本。)我认为 bash 仍在从旧位置启动 python,但该位置并未反映在 python 的sys.argv[0] 中。因此,python 本身使用了 sys.executable 的虚假值。显然,这会破坏一切。
    • 顺便说一句,感谢您指向 python 源代码中的相关行。如果该代码在 Python 3 中仍然相同,那么听起来有人需要提交一个补丁来检查 shell hash 表,而不是仅仅搜索 PATH
    【解决方案2】:

    Bash 在内存中保留一个缓存的查找表,您可以使用hash 检查它。如果您向您的PATH 添加一个与您之前在不同位置使用过的程序同名的程序,bash 仍会记住旧位置。 env 显然绕过了这个缓存;或者您可以使用hash -r python 将其删除。

    还要注意which 是不可移植的,而且通常不是正确使用的工具; type 由 POSIX 指定,内置于任何现代 shell。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-16
      • 2016-11-23
      • 1970-01-01
      • 1970-01-01
      • 2011-03-19
      • 2014-03-03
      • 2020-01-07
      • 2012-09-21
      相关资源
      最近更新 更多