背景
最近在通过shell脚本在Linux系统安装Java或Python的过程中,遇到了shell脚本中的“source /etc/profile”无法生效的问题,虽然也可以在执行完脚本后再次执行“source /etc/profile”来使配置文件生效,但未免有些繁琐,而我又比较懒,想彻底弄清其原因及解决办法,从而一劳永逸。以下为本次解决问题的实践记录:
1.示例
如下图所示,在python_install.sh脚本中,在安装完Python3、配置完环境变量后,使用source /etc/profile 命令来重新加载配置文件,并更改Python的安装镜像源。但通过./python_install.sh执行脚本完成后,在命令行输入:python3,仍然提示“-bash: python3: command not found”(表示重新加载配置文件未生效,系统无法识别到python3命令)
2.原因
执行脚本时,脚本中的命令是在子shell中执行,子shell只能继承父shell的环境变量,而无法修改父shell的环境变量,所做的修改仅对当前子shell有效。所以,当脚本执行完成,回到shell命令行,原子shell脚本中执行的source命令也就不生效。
3.解决办法
1)方法一:
# 也就是上述提到的繁琐的方法./python_install.sh #(或sh python_install.sh)source /etc/profile
2)方法二(本文主要想表达的方法):
# 通过source方式执行脚本source python_install.sh #(或. python_install.sh注意点后面有空格)
4.shell中"."、"source"、"sh"、"./"的区别
命令 |
作用 |
作用域 |
source,等价于.(点) |
用于使shell读取指定的shell文件,并依次执行文件中的所有语句 |
作用于当前shell进程,注意头部一定要声明是bash,而不是sh |
sh |
执行指定shell脚本,在子shell中执行脚本中的语句 |
创建一个子shell,在新的namespace中执行此脚本,继承父shell环境变量,但不改变父shell环境变量,仅对当前子shell有效 |
./ |
执行当前脚本文件,前提是待执行的文件具有可执行属性,等价于sh |
创建一个子shell,在新的namespace中执行此脚本,继承父shell环境变量,但不改变父shell环境变量,仅对当前子shell有效 |
5.其他注意事项
若shell脚本中使用了source命令,则需要使用bash(或source)来执行,因为sh和bash是不同的shell,source命令是bash shell的内置命令,从C Shell 而来,而sh中没有source命令,所以用sh或者./运行的时候,会开启一个子shell进程,子shell进程继承了父shell(无source命令)的特性,所以会报错“source: not found”。
6.卸载python3,再次使用脚本进行安装
rpm -qa|grep python3|xargs rpm -ev--allmatches--nodeps# 卸载python3whereis python3 |xargs rm-frv# 删除python3所有残余文件,注意是卸载Python3,千万要带3,否则会把系统自带的Python2和yum(依赖Python2)也卸载了whereis python3 # 查看是否存在python3python3 # 进入python解释器环境,若提示“-bash: python3: command not found”则说明卸载成功
再次执行shell脚本,一键安装python
source python_install.sh
安装成功后如下图所示:
验证一下python3是否安装成功,以及脚本最后更改的pip镜像源是否生效:
从上图可以看出,python3安装成功,python镜像源已成功替换为阿里云镜像源。
小结
以上就是shell脚本中“source /etc/profile”无法生效的原因及解决办法,以及shell中"."、"source"、"sh"、"./"的区别,只要脚本中使用了“source /etc/profile”,就可以使用:source xxx.sh(脚本文件名称)来执行脚本,从而自动重新加载配置文件。