环境变量
环境变量
为什么需要环境变量?
为了将软件的配置与代码分离,从而实现同一程序在不同环境下无需修改就能灵活运行。
什么是环境变量?
它是操作系统提供的全局动态键值对,用于向进程传递运行所需的配置和上下文信息。
就比如, 想要运行一个程序, 使用自己编译的程序和安装在 /usr/bin 目录下的程序做对比, 拷贝一份到该目录下, 运行它就不需要添加路径, 而在工作目录下运行该程序就需要带上 ./ 这就是在指明路径. 这就引出一个重要的环境变量: PATH, 它是操作系统安装的可执行程序的默认搜索路径. 操作系统拿到用户提供的指令时, 会从 PATH 中的目录一个一个找, 如果找不到就会返回一个错误消息, 找到了就会执行该指令.
再比如, 执行 pwd 指令的时候, 它是如何知道我当前路径在哪里的? 通过 env | grep PWD 我们就可以看到, PWD 是一个环境变量, 它动态地记录着用户当前的工作目录, 所以使用 pwd 指令的本质, 就是打印 PWD 的值.
再比如, 某个文件只允许root用户执行, 但操作系统它是如何知道当前用户是 root 用户还是普通用户?
答: 还是环境变量, USER 是存储当前用户名的环境变量.
再衍生到另一个概念, 我们平时使用的提权指令: sudo 它的本质就是临时改变了系统用来描述用户的环境变量, 让用户可以有权限临时执行条特权指令.
还有, ls 指令为什么不带参数的时候默认是打印当前工作目录包含的目录和文件? 这里还是 PWD变量的关系, 如果不带参数的话, 准确来说, 该指令应该是 ls $PWD. 自然就是输出当前目录下的所有文件和目录了.
综上, 回想一下, 如果没有环境变量, 使用系统的复杂度一定会提高不少罢(悲).
Note: 这里的全局并不是整个操作系统都有效的意思, 而是在当前进程和其子进程中有效. 换句话说, 它的作用域就在其本身和它的子进程.
证明: 在一个bash中使用export命令定义一个环境变量, 就会发现, 在其他bash中找不到这个变量. 而由定义该环境变量的bash创建的子进程可以使用该环境变量.
环境变量的组织方式
每个进程都会收到一张环境变量表, 该表是一个字符指针类型的数组. 每个指针指向一个以 "\0" 为结尾的字符串. 这些字符串的内容, 就是环境变量!
Note: 没错, 环境变量的本质是在特定的内存区域中的一个一个的
char *类型的字符串.
当执行一条命令, 比如 ls 时, 我们的shell就会去环境变量表中的PATH变量中查找, 有没有含有 ls 命令的目录, 查到了就执行, 没查到就会返回错误.

环境变量相关的命令
- echo: 显示某个环境变量值
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
环境表, 每个进程都会收到一张环境变量表, 它是一个字符指针类型的数组, 每个指针指向一个字符串?
如何使用环境变量?
- 命令行参数
int main(int argc, char * argv[], char * env[]) {
int i = 0;
//遍历环境变量表, 并打印所有的环境变量到屏幕上
//功能类似于env命令
for (; env[i]; i++) {
printf("%s\n", env[i]);
}
return 0;
}
- 通过外部变量
environ
int main(int argc, char * argv[]) {
extern char * environ[];
int i = 0;
while (environ[i]) {
printf("%s\n", environ[i]);
i++;
}
return 0;
}
- 使用系统调用接口(推荐)
int main(int argc, char * argv[]) {
//环境变量表是一个指向字符指针数组的一个指针
//获取每个环境变量也就意味着我要获取的是一个数组指针
//所以
char * env = getenv("PATH");
printf("%s\n", env);
}
环境变量的全局性
在父进程中定义的环境变量, 在子进程中可以被获取.
比如我在 bash 中定义一个环境变量 HOMO
export HOMO=114514
再使用如上代码获取
printf("%s", getenv("HOMO"));
输出结果:
114514
浙公网安备 33010602011771号