【原创】Ubuntu 普通用户安装 PyInstaller 后提示找不到命令

相关环境

Ubuntu 18.04.4
Python 3.6.9
Pip 9.0.1
Pyinstaller 4.0

问题描述

在 Ubuntu 上用普通用户使用 pip3 安装 pyinstaller 成功了,但却发现执行 pyinstaller 命令时报错提示找不到该命令:

$ pip3 install pyinstaller -i https://pypi.douban.com/simple
Collecting pyinstaller
  Downloading https://pypi.doubanio.com/packages/82/96/21ba3619647bac2b34b4996b2dbbea8e74a703767ce24192899d9153c058/pyinstaller-4.0.tar.gz (3.5MB)
    100% |████████████████████████████████| 3.5MB 561kB/s 
Collecting altgraph (from pyinstaller)
  Downloading https://pypi.doubanio.com/packages/ee/3d/bfca21174b162f6ce674953f1b7a640c1498357fa6184776029557c25399/altgraph-0.17-py2.py3-none-any.whl
Collecting pyinstaller-hooks-contrib>=2020.6 (from pyinstaller)
  Downloading https://pypi.doubanio.com/packages/2a/e6/4a47a7d41266cbca531bed3031c6412f9601ba2a2319e6d8c43f6917c51d/pyinstaller_hooks_contrib-2020.10-py2.py3-none-any.whl (166kB)
    100% |████████████████████████████████| 174kB 9.3MB/s 
Collecting setuptools (from pyinstaller)
  Downloading https://pypi.doubanio.com/packages/6d/38/c21ef5034684ffc0412deefbb07d66678332290c14bb5269c85145fbd55e/setuptools-50.3.2-py3-none-any.whl (785kB)
    100% |████████████████████████████████| 788kB 2.1MB/s 
Building wheels for collected packages: pyinstaller
  Running setup.py bdist_wheel for pyinstaller ... done
  Stored in directory: /home/jiangzl/.cache/pip/wheels/b2/b1/e4/dcab76aa7f2a453aad3bdc503b11d578ae8229251e3014c6db
Successfully built pyinstaller
Installing collected packages: altgraph, pyinstaller-hooks-contrib, setuptools, pyinstaller
Successfully installed altgraph-0.17 pyinstaller-4.0 pyinstaller-hooks-contrib-2020.10 setuptools-50.3.2
$
$ pyinstaller -v
pyinstaller: command not found

问题分析

1、查看你的 PATH

从现象来看,这个 pyinstaller 应该是正常安装了,但找不到命令就可以判断 pyinstaller 可执行文件的位置不在 PATH 中了。执行如下命令查看你的 PATH 包含的目录

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

看起来这些目录中都没有 pyinstaller 的文件。

2、查找 pyinstaller 的位置

一般来说,在 Linux 上使用非 root 用户安装软件的可执行文件位于 /usr/local/bin,但 /usr/local/bin 在 PATH 中,显然 pystaller 不在 /usr/local/bin 下。

$ ll /usr/local/bin | grep pyinstaller

另外两个非 root 用户常安装的位置是 ~/bin 和 ~/.local/bin。遂逐一检查,发现家目录中无 bin 目录,而在 ~/.local/bin 下果然发现了 pyinstaller 可执行文件

$ ll ~/.local/bin/
total 40
drwxrwxr-x 2 jiangzl jiangzl 4096 Nov  1 02:27 ./
drwx------ 5 jiangzl jiangzl 4096 Nov  1 02:27 ../
-rwxrwxr-x 1 jiangzl jiangzl  234 Nov  1 02:27 easy_install*
-rwxrwxr-x 1 jiangzl jiangzl  234 Nov  1 02:27 easy_install-3.6*
-rwxrwxr-x 1 jiangzl jiangzl  242 Nov  1 02:27 pyi-archive_viewer*
-rwxrwxr-x 1 jiangzl jiangzl  237 Nov  1 02:27 pyi-bindepend*
-rwxrwxr-x 1 jiangzl jiangzl  240 Nov  1 02:27 pyi-grab_version*
-rwxrwxr-x 1 jiangzl jiangzl  236 Nov  1 02:27 pyi-makespec*
-rwxrwxr-x 1 jiangzl jiangzl  221 Nov  1 02:27 pyinstaller*
-rwxrwxr-x 1 jiangzl jiangzl  239 Nov  1 02:27 pyi-set_version*

3、查看环境变量文件

查看 .bash_profile .bash_login .profile .bashrc 等环境变量文件,查看是否有将 ~/.local/bin 添加到 PATH 环境变量中。

经过一番查找,发现没有 .bash_profile .bash_login 文件,.bashrc 中没有定义 ~/.local/bin 相关内容。

但在 ~/.profile 中却发现了 ~/.local/bin,如下图所示:

那么问题来了,明明 .profile 文件中已经定义了 PATH="$HOME/.local/bin:$PATH",为什么还会在安装 pyinstaller 成功以后出现找不到命令的问题呢?请看下文

问题原因

这个问题其实算是 Ubuntu 中的一个 BUG。造成这个问题的原因有三个:第一个 Linux 中可执行命令的查找机制,第二个是 Linux 加载用户环境变量文件的机制,第三个是 .profile 中配置 PATH 的方式。

1、Linux 下查找可执行命令的机制

Linux 下查找可执行命令的机制就是从 $PATH 环境变量的目录中从前往后按顺序从一个目录一个目录地找,如果找不到就会报命令找不到的错误。

2、Linux 加载用户环境变量文件的机制

Linux 加载用户环境变量文件的机制的详细过程不在此介绍了,但其中有一点是与这个问题有关的。那就是用户的环境变量文件只会在用户 login shell 的时候加载文件中的内容并生效。

所以,当用户登录后对该文件进行了更新时,更新的内容不会立刻生效,需要手动执行 source ~/.profile 才能生效,或者退出当前的 login 再次登录...

3、这天秀的判断

可是,这个 .profile 的文件我也没进行更新啊,为什么还有出了问题呢???请注意上面截图中红色区域的 shell 代码。

这里有两个判断,就是判断如果存在 $HOME/bin 和 $HOME/.local/bin 目录,便将其添加到 $PATH 环境变量中。

这两个判断本身看着没有任何问题,但结合第一点的机制就可能会出现了这个 BUG。

4、问题过程

(1) 用户 jiangzl 使用 ssh 登录第一次 shell 环境,此时 bash 会加载 .profile 文件(系统默认生成的)

(2) bash shell 读到 .profile 中的判断,然后判断 /home/jiangzl 目录下有没有 bin 与 .local/bin 目录,然后发现没有这两个目录。自然地 $PATH 中也就没有 ~/bin 和 ~/.local/bin

注意:这两个目录不是默认就创建的,一般刚创建的用户第一次登录或者从来没安装过第三方软件是不会有这两个目录的。

(3) 这时候,用户 jiangzl 使用 pip install pyinstaller 安装了 pyinstaller 软件,安装成功后生成了 ~/.local/bin 目录并将 pyinstall 可执行文件放入了 ~/.local/bin 目录。

(4) 于是,~/.local/bin 由于不在 $PATH 中,自然就不能正常运行 pyinstaller 命令了。

解决方法

这个问题的解决方法其实非常简单,也有很多种解决方法

1、退出当前会话重新登录 shell

这个解决方法就是根据 bash shell 加载环境变量机制来实现的,稍显麻烦了。

2、使用 source 命令使环境变量重新生效

执行如下命令使 .profile 环境变量重新生效

source ~/.profile

这种方法最简单,推荐使用了~

3、更改 .profile 中的判断逻辑

将 .profile 中的 ~/bin 与 ~/.local/bin 添加 PATH 的判断逻辑去掉,也就是说不管有没有这两个目录,都将其添加到 $PATH 环境变量中

# set PATH so it includes user's private bin if it exists
export PATH="$HOME/bin:$PATH"
#

# set PATH so it includes user's private bin if it exists

export PATH="$HOME/.local/bin:$PATH"

此方法相对较为麻烦,不建议使用此方法。

总结

1、这个问题不是安装 pyinstaller 才会出现的问题,而是由于 Ubuntu 相关机制引发的小小 BUG,相信看过上面的分析就知道了

2、该问题一般在用户第一次安装第三方软件时可能会出现,特别是将软件安装为用户专有软件时。

You may also like...

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注