前面的文章中讲述了孤儿进程、进程的优先级等概念,本文中继续进程的概念——环境变量:
基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
PATH
为什么我们在Linux下的编写的程序需要使用 ./ 来运行?可以知道我们自己的编写的程序与Linux下的部分指令本质上没有任何的区别。如果我们也想让我们自己编写的程序运行不需要使用 ./ 那么不就跟系统里的指令一样了吗,下面就来试一下:
上述原因在于默认的程序,在系统中存在一个环境变量中,这个环境变量可以通过该变量在系统中的特定路径下搜索对应的指令的。执行一条命令的前提是找到这条命令。 下面的PATH就是一个环境变量。 PATH中的路径以:作为分割从左向右一次寻找。
前面讲过可以使用which指令查找指令所在的位置:
从上面的两张图中就可以看到当我们从根目录开始的时候两者都可以运行,但是在查找时 ls 指令可以找到位置,而我们自己的指令就无法找到。 这也就是为什么我们的指令不添加 ./ 就无法运行。
使用指令 export PATH=$PATH: + 程序所在的路径,添加完之后就可以不使用 ./ 就可以运行我们的程序了。或者我们也可以将我们的文件拷贝到环境变量中系统的指令集中。此时,同样可以运行。
下图有一条错误的指令使用后会发现:确实使用我们自己编写的myproc不用在使用 ./ ,但是系统的一些指令使用也会报错:
因为我们直接将当前的路径覆盖掉了原先环境变量中的信息,重新启动xshell就会重新加载环境了
HOME
echo $HOME;cd ~; pwd
和环境变量相关的命令
- echo: 显示某个环境变量值
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
环境变量的组织形式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
通过代码获取环境变量
首先,要讲的是main函数有三个参数分别为:int argc, char *argv[], char *env[],其中第三个变量表示一个指针数组,数组中放入的都是char*类型,指向的都是一个环境字符串,最后都要以NULL结束。还有前两个参数后面再谈。
命令行的第三个参数
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
for(; env[i]; i++)
{
printf("%s\n", env[i]);
}
return 0;
}
通过第三方变量environ获取
#include <stdio.h>
int main(int argc, char *argv[])
{
extern char **environ;
int i = 0;
for(; environ[i]; i++)
{
printf("%s\n", environ[i]);
}
return 0;
}
// libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
通过系统调用获取
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * pwd = getenv("PWD");
if(pwd)
{
printf("PWD:%s\n", pwd);
}
return 0;
}
这样我们就自己编写了一个pwd指令。同样,使用环境变量还可以对用户进行控制。
char* own = getenv("USER");
if(own == NULL)
{
perror("getenv");
}
else
{
if (strcmp(own, NAME) == 0)
{
printf("程序允许执行...\n");
}
else
{
printf("当前用户 %s 非法\n", own);
}
}
环境变量本质就是一个内存级的一张表,这张表由用户登录系统的时候,进行给定用户形成属于自己的环境变量表。环境变量中的每一个都有自己的用途:有的是进行路径查找的,有的是进行身份认证的,有的进行动态库查找的,有的是用来确认当路径等等。每一个环境变量都有自己的特定应用场景,每一个元素都是kv的。这些都是在系统的相关配置文件中读取进来的。
环境变量通常是具有全局属性的
环境变量通常具有全局属性,可以被子进程继承下去
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * env = getenv("MYENV");
if(env)
{
printf("%s\n", env);
}
return 0;
}
直接查看,发现没有结果,说明该环境变量根本不存在
导出环境变量
export MYENV="hello world"
父进程
子进程
如果我们编写时没有添加export就无法正常的显示:(shell的本地变量,只在shell内部有效)
当我们使用 export 将其声明为环境变量之后就可以变成环境变量,添加到环境变量表中:
在Linux下的 . 表示source表示让后面跟的配置文件立马生效。
上面我们说过可以使用export将本地变量变成环境变量,如果我们不想要这个环境变量之后可以使用 unset 指令将这个环境变量取消掉。