Python中sys.executable和sys.version之间不匹配

时间:2014-03-06 21:45:42

标签: python linux sudo env

安装了两个Python解释器:

[user@localhost ~]$ /usr/bin/python -V && /usr/local/bin/python -V
Python 2.4.3
Python 2.7.6

Sudo为其运行的每个命令更改PATH,如下所示:

[user@localhost ~]$ env | grep PATH && sudo env | grep PATH
PATH=/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/user/bin
PATH=/usr/bin:/bin

我运行测试脚本:

[user@localhost ~]$ cat what_python.py
#!/usr/bin/env python

import sys
print sys.executable
print sys.version
[user@localhost ~]$ sudo python what_python.py
/usr/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

并获取sys.executable中的Python 2.4.3和sys.version中报告的2.7.6版的路径。显然,sys.executablesys.version不匹配。考虑到sudo如何修改PATH,我可以理解sys.executable的价值。但是,为什么sys.version报告版本2.7.6而不是版本2.4.3,它会匹配usr/bin/python报告的sys.executable路径?

这是我的问题Sudo changes PATH, yet executes the same binary

的后续跟进

3 个答案:

答案 0 :(得分:5)

两个@Graeme

  

python可能无法检索到这一事实表明它   正在进行自己的PATH搜索(...)

和@twalberg

  

(...)看起来sys.executable搜索当前的PATH而不是   解析argv [0](或者因为argv [0]在这里是简单的python   case ...),(...)

基本上是正确的。我不愿意相信Python做的事情如此简单(愚蠢?),而不是使用PATH来定位自己,但这是真的。

Python的sys模块在​​Python/sysmodule.c文件中实现。从版本2.7.6开始,sys.executable设置为1422行,如下所示:

 SET_SYS_FROM_STRING("executable",
                     PyString_FromString(Py_GetProgramFullPath()));

Py_GetProgramFullPath()函数在文件Modules/getpath.c中定义,从第701行开始:

char *
Py_GetProgramFullPath(void)
{
    if (!module_search_path)
        calculate_path();
    return progpath;
}

函数calcuate_path()在同一文件中定义,包含以下comment

/* If there is no slash in the argv0 path, then we have to
 * assume python is on the user's $PATH, since there's no
 * other way to find a directory to start the search from.  If
 * $PATH isn't exported, you lose.
 */

从我的情况可以看出,当导出的$PATH上的第一个Python与正在运行的Python不同时,也会丢失。

有关计算解释程序可执行文件位置的过程的更多信息,请参见getpath.c [user@localhost ~]$ sudo /usr/local/bin/python what_python.py /usr/local/bin/python 2.7.6 (default, Feb 27 2014, 17:05:07) [GCC 4.1.2 20080704 (Red Hat 4.1.2-54)] 文件的top

  

在完成任何搜索之前,可执行文件的位置是   决心。如果argv [0]中有一个或多个斜杠,则使用它   不变。否则,必须从shell的路径调用它,   所以我们在$ PATH中搜索命名的可执行文件并使用它。如果   在$ PATH上找不到可执行文件(或者没有$ PATH环境   变量),使用原始的argv [0]字符串。

     

接下来,检查可执行位置以查看它是否是符号   链接。如果是这样,链接被追逐(正确解释一个亲戚   pathname(如果找到)并使用链接目标的目录。

让我们做几个测试来验证上述内容:

如果argv [0]中有一个或多个斜杠,则不加改变

[user@localhost ~]$ sudo PATH= python what_python.py
<empty line>
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

确定。

如果在$ PATH上找不到可执行文件(或者没有$ PATH环境变量),则使用原始的argv [0]字符串。

PATH

错误。在这种情况下,来自sys模块的documentation的语句为真 - 如果Python无法检索其可执行文件的真实路径,则sys.executable将为空字符串或None。

让我们看看是否将python的二进制文件的位置添加回[user@localhost ~]$ sudo PATH=$PATH python what_python.py /usr/local/bin/python 2.7.6 (default, Feb 27 2014, 17:05:07) [GCC 4.1.2 20080704 (Red Hat 4.1.2-54)] (在sudo删除它之后)修复问题:

{{1}}

确实如此。

相关:

  • Python问题7774 - sys.executable:如果修改了zeroth命令参数,则位置错误。
  • Python问题10835 - sys.executable default和altinstall
  • python-dev邮件列表thread - 更严格的sys.executable定义
  • Stackoverflow question - 如何在C
  • 中查找可执行文件的位置

答案 1 :(得分:1)

我认为/usr/local/bin/python是正在运行的可执行文件。版本字符串几乎可以肯定地编译成python,所以它不太可能出错。查看sys.executable的文档:

  

sys.executable

     

一个字符串,给出Python解释器的可执行二进制文件的绝对路径,在有意义的系统上。如果Python无法检索其可执行文件的实际路径,则sys.executable将为空字符串或None。

python可能无法检索到这一事实表明它正在使用PATH sudo设置进行自己的PATH搜索(根据我对上一个问题的回答)与用于查找可执行文件的内容不同。

这里唯一明确的方法是深入研究python实现,但一般来说我会说版本字符串更可能是你可以信任的。另一方面,sudo使用execve来执行命令(至少根据man页面)。您必须将可执行文件的完整路径指定为execve(某些exec变体会执行自己的PATH搜索,但这一点不会。因此,python填写sys.executable

我不知道是否有任何方法可以获得argv[0]解释器的实际pythonsys.argv[0]始终是脚本的名称或-c) ,但这会很有趣。如果是/usr/local/bin/python,这将是python中的错误。

我认为最好的办法就是在secure_path中设置/etc/sudoers,希望您能获得一致性。

更新

实际上execve接受可执行路径的参数,然后是argv数组,因此argv[0]不一定是/usr/local/bin/python。你仍然可以通过制作如下脚本来找到它:

import time
time.sleep(60)

然后运行它并获取ps给你完整的参数:

sudo python sleep.py &
ps -o args= -C python

另外,为确保正在运行python,您可以执行以下操作:

sudo ls -l /proc/PID/exe
程序运行时

答案 2 :(得分:0)

每次启动python解释器时,shell都会转到/ usr / bin / python并执行它(请尝试下一步:python -c&#34; import os; print(os.environ [&#39; _&#39 ;])&#34)。

那么,你可以看到自己ln -l | grep python / usr / bin / python是python解释器可执行文件的软链接。

我做的是:

  1. 安装最新版本的python(转到python的网站, 下载最后一个代码configure && make && make install
  2. 检查此最新版本可执行文件的位置。
  3. 删除/ usr / bin / python软链接##(您需要root权限 须藤)
  4. ln -s <location最后一个python版本的可执行文件&gt;在/ usr / bin中/蟒蛇 ##(很可能需要sudo)
  5. 从命令行执行python。
  6. import sys
  7. sys.version ##它应该是最后一个。