文章目录
1. 环境变量的概念
**环境变量(environment variables)**一般是指在操作系统中用来指定操作系统运行环境的一些参数。
例如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
如果你以前在你的Windows笔记本上安装过Java或者python的开发环境,那么你大概率配置过环境变量PATH
那么PATH到底是什么呢?
2. 常见的环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的工作目录(即用户登录Linux机器后所在的默认目录位置)
- SHELL:当前的shell,它的值一般是/bin/bash.
3. 查看环境变量的方法
- 使用
echo $NAME
来查看指定环境变量,其中NAME
就是你要查看的环境变量的名字
- 使用
env
指令可以查看到当前shell运行的所有环境变量
4. 测试PATH
大家有没有想过一个问题:我们自己的代码编译产生的可执行程序和系统自带的指令有什么区别,为什么系统自带的指令能够直接运行,但是我们自己写的代码就不能直接运行,而是需要加上对应的路径?
对于这个问题,我们可以理解成:要执行一条指令(运行一个程序),就要先找到他的位置,我们自己写的程序的位置需要被指定,但是像ls这种系统自带的指令的位置,已经提前被写到PATH环境变量里面了。我们看一下ls的位置
那么我们再来查看一下PATH下的路径有哪些:
可以看到PATH中有很多路径,这些路径通过:
隔开,那么其中就有我们看到的ls
指令的所在路径/usr/bin
。在使用ls命令时,系统就会查看环境变量PATH,然后默认从左到右依次在各个路径当中进行查找。因此使用ls
指令的时候不带路径也能找到。
知道了不用带路径就能执行的原理之后,那么怎么让我们自己写的程序也能够不带路径执行呢?
根据我们上述的PATH的原理,那么就让PATH中的某一个路径包含我们的程序即可,这里提供两种方法:
1. 将可执行程序拷贝到环境变量PATH的某一路径下
根据我们的分类,这里选择拷贝到/usr/bin目录下
但是非常不建议这么做,因为我们写的程序没有经过测试,会污染系统指令池
2. 将我们写的程序的所在路径添加到PATH中
export PATH=$PATH:指定路径
注意:这里一定要在指定的路径前面加上$PATH
,否则之前的路径就被覆盖了
环境变量是怎么来的?
我们输入指令的地方是一个命令行解释器,命令行解释器也是能够定义变量的
当我们登录Linux机器的时候,会自动定义很多变量,这些变量就是环境变量
在用户家目录可以看到有个文件
.bash_profile
,这个文件内部就是一个创建环境变量的脚本,在用户登录的时候就会自动执行脚本,创建很多个内存级的环境变量
5. 和环境变量有关的命令
-
echo: 显示某个环境变量值
-
export: 设置一个新的环境变量
-
env: 显示所有环境变量
-
unset: 清除环境变量
-
set: 显示本地定义的shell变量和环境变量 (这里和env做一下区分,env只能显示环境变量,在shell中定义的本地变量,没有经过export之前在env中不显示,但是在set中显示)
一些常见的环境变量的含义
环境变量名称 | 含义 |
---|---|
PATH | 命令的搜索路径 |
HOME | 用户的主工作目录 |
SHELL | 当前Shell |
HOSTNAME | 主机名 |
TERM | 终端类型 |
HISTSIZE | 记录历史命令的条数 |
SSH_TTY | 当前终端文件 |
USER | 当前用户 |
邮箱 | |
PWD | 当前所处路径 |
LANG | 编码格式 |
LOGNAME | 登录用户名 |
6. 环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
7. 通过代码获取环境变量
7.1 通过命令行的第三个参数
我们在学习C语言的时候,见到的第一个经典的代码是是一个打印”hello world”的代码
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
我们在进行后续的语言的学习的时候,一直写的main函数都是没有参数的,那么main函数可以有参数吗?
答案是可以
在一些地方我们能见到这种main函数的定义方式
int main(int argc, char* argv[])
所以main函数是具有参数的,那么这些参数是什么含义呢?我们使用一段代码来测试一下
编译运行可以发现,main函数的第二个参数(一个指针数组),数组中的第一个字符指针存储的是可执行程序的位置,其余字符指针存储的是所给的若干选项,最后一个字符指针为空。第一个参数就是这个数组内元素的个数
有了以上的基础之后,我们来看一看mian函数的第三个参数:(对,没错,main函数一共可以有三个参数)
main函数的第三个参数接收的实际上就是环境变量表,我们可以通过main函数的第三个参数来获取系统的环境变量
int main(int argc, char *argv[], char *envp[])
7.2 通过第三方变量environ
除了使用main函数的第三个参数来获取环境变量之外,还可以通过第三方变量:environ来获取到环境变量
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明
运行此代码同样能够获取到环境变量。
8. 通过系统调用获取
除了使用指令来获取环境变量之外,还能够通过系统调用(system call)来获取环境变量
这里介绍一个系统调用:getenv
getenv
可以根据所给出的环境变量名在环境变量表中搜索,并返回一个对应的字符串指针,如果没找到就返回NULL
例如:
9. 环境变量的全局属性
为什么我们说环境变量具有全局属性,他是怎么实现的呢?
环境变量具有全局属性是因为它们在整个操作系统中可见且可访问。当一个进程启动时,它会从父进程继承一份环境变量的副本,并且可以修改、添加或删除这些变量。
当你在命令行中设置或修改一个环境变量时,此更改将在当前 Shell 进程中生效,并且可以影响该 Shell 进程及其后续启动的子进程,而我们一般运行的进程都是Shell的子进程,因此其他进程和 Shell 可以看到并使用同样的环境变量,也就实现了环境变量的全局性。
操作系统中可见且可访问。当一个进程启动时,它会从父进程继承一份环境变量的副本,并且可以修改、添加或删除这些变量。
当你在命令行中设置或修改一个环境变量时,此更改将在当前 Shell 进程中生效,并且可以影响该 Shell 进程及其后续启动的子进程,而我们一般运行的进程都是Shell的子进程,因此其他进程和 Shell 可以看到并使用同样的环境变量,也就实现了环境变量的全局性。
本节完…