背景:我们的项目使用了superset(Airbnb开源的数据挖掘平台),superset的运行需要python2.7环境,以前项目部署时候都是手动安装python2.7,然后再安装产品。最近接了一个自动升级python的需求,在开发过程中被linux的环境变量坑了一会。
- 问题1:Python2.7安装完后,为什么执行python -V 还是2.6
- 问题2:安装过程中进行Python编译,包make命令command not found是什么鬼?
Linux的环境变量一般是这样的(执行echo $PATH):/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/usr/games:/opt/setsuse/SEK/Tcl
其中/usr/local/bin放的的用户安装软件的命令目录,/usr/bin放的是系统自带软件的命令目录。
也就是说,执行命令的时候会先/usr/local/bin中查找命令是否存在,存在则执行,不存在再继续往下一个目录查找。如果所有目录都找不到命令,就会报命令找不到错误。(所以一般出现command not found,先检查环境变量)
但是如果处于各种各样的原因,(人工或者一些系统配置)修改了环境变量,或者多个目录下存在命令的情况,那么命令执行就会出现奇怪的问题了。
以上背景内容可忽略
为什么安装完Python2.7后执行python -V还是2.6
因为/usr/bin中有一个python软链接,指向Python2.6(系统自带),如果在命令行直接执行python -V,会先在/usr/bin执行python(指向Python2.6),所以调用到的其实还是Python2.6。
解决方案:
方法1:执行命令的时候加上安装目录
/usr/local/bin是python2.7的默认安装目录,如果安装时候更改了安装目录,则换成安装的那个目录
1 | /usr/local/bin/python -V |
方法2:修改/usr/bin下的python软链接,让其执行python2.7
1 | rm /usr/bin/python |
为什么安装过程中sudo执行bash脚本来编译Python包,提示sudo make command not found
因为linux使用sudo执行脚本,在运行脚本内容的shell中,环境变量发生了改变。
做个实验:写一个bash脚本path.sh,内容如下:
1 | #!/bin/bash |
1 | sudo ./path.sh |
直接执行sudo和sudo执行脚本使用的环境变量是不一样的。这就是sudo执行脚本找不到命令的原因。
因为linux在sudo执行脚本的时候,会将shell的环境变量重置。(下方的env_reset配置)
1 | sudo -l |
解决方案:各有利弊
方案1:在脚本中加入环境变量配置
1 | #!/bin/bash |
优点:方便快捷
弊端:如果在脚本中,使用sudo 去调用其他脚本,其他脚本也要再次配置$PATH,否则一样会找不到命令
方案2:使用sudo执行脚本带上“-E”参数,则执行脚本内容时会带上当前shell的环境变量
1 | sudo -E ./path.sh |
优点:方便快捷
弊端:同样的,如果在脚本中需要sudo调用其他脚本,也要带上“-E”参数
方案3:在脚本中执行命令带上安装目录,就像上个问题中解决python找不到2.7问题是一样的原理。
优点:一般不会再出现command not found问题
弊端:增加脚本复杂度,每个命令都要知道其安装目录
方案4:在/usr/bin中使用软链接,跳转到命令所在目录。就像上个问题中增加python软链接到python2.7一样。
优点:一般不会再出现command not found问题,而且其他地方也可以使用。
弊端:需要提前知道要使用的命令,当时加上一次之后,所有脚本都可以使用。
为什么unzip解压命令没有用?
在一个安装python的脚本需要解压文件进行编译,但是发现第一次执行解压、编译没问题,但是后面就编译失败了,苦思无解。幸好有个大神指出了问题所在。
在bash脚本执行写作过程中,特别要注意一些 有可能 需要交互的命令。
例如unzip,如果解压文件已存在,则会提示是否进行覆盖,此时如果没有在bash脚本中进行输入,则会shell会一直等待输入至命令超时(命令等待超时后的动作视不同实现决定)。
解决方案:
- 熟悉命令的不同参数,一般都会有规避方法。例如unzip 有参数-o 表示强制覆盖
- 也有一些自动输入的方式,例如
1 | echo 'abc' | unzip xxxx |
为什么有一些脚本执行到一半就失败了?
在执行升级ptyhon的bash脚本过程中,执行config到一半就停止了,没有任何报错。折腾半天也没明白,config这条linux命令为什么会执行到一半戛然而止。
幸好大神一眼洞穿,表示踩过这个坑。
在执行bash脚本的过程中,shell的缓存区是有限大小(据说是1k),但缓冲区占满后,命令执行会中止。
因为我的脚本中编译python整个过程有很多打印,所以导致了缓存区占满了。
解决方案:
一般bash脚本中执行命令会选择把输入打印到文件,一方面避免了缓存区占满问题,一方面也有利于后续问题定位。
1 | ./config >> /var/log/xx.log |