环境变量概念
环境变量是在一些操作系统中,运行环境的参数
当我们运行操作系统时,操作系统为自己开辟了一块空间,这块空间里存储了一些参数变量,当我们要使用时,我们可以直接那这些参数来用。
查看环境变量
当我们在执行我们自己可执行文件时,我们需要加上路径,但当我们执行操作系统的可执行文件时却不需要加上路径,这是为什么
这是因为操作系统配置了环境变量
echo $PATH
通过这个指令我们可以查找那些目录中的文件是可以直接执行的
其中PATH是一个环境变量,在这个环境变量下面的所有目录位置的可执行文件都不需要加路径就可以直接执行
当我们输入一个指令时,系统会在这个目录下面找这个指令是否存在,若存在,则执行该指令,若不存在,则报错
我们也可以修改PATH所对应的路径,以便我们可以直接执行我们的程序,不需要加路径
我们来测试一下
#include<stdio.h>
int main()
{
printf("Hello,World\n");
}
执行可执行文件,不加路径,执行失败
我们将该路径加到PATH环境变量中
我们再次执行文件
执行成功
但是当我们重启操作系统后PATH环境变量也会还原为之前的状态
我们也可以直接修改环境变量位置
PATH=/root/working8
但是这样会导致我们一些常用的指令无法使用,比如ls
但是我们只要重启系统就可以恢复了
还有几个重要的环境变量
PWD:记录当前路径
HOME:记录家目录位置
USER:记录当前用户
创建环境变量
我们可以通过export来创建环境变量
不过当系统重启时我们自己创建的环境变量就失效了
查看所有环境变量
通过env指令可以查看所有环境变量
env
这里我们只管查一部分环境变量
其中有我们熟悉的USER和PATH,还有一个我们刚刚自己创建的一个变量youenv
在程序中查看环境变量
getenv
getenv是一个函数,它存在<stdlib.h>头文件中,当执行它时,输入一个字符串,会返回一个对应字符串的环境变量,
#include<stdio.h>
#include<stdlib.h>
int main()
{
const char * ch1=getenv("PATH");
const char * ch2=getenv("USER");
printf("%s\n",ch1);
printf("%s\n",ch2);
}
输出结果
getenv是最常用的获取环境变量的方式
environ
environ是一个指针数组,里面存的是char*指针,指针指向的就是环境变量,它是一个外部变量,我们需要用extern将它拿来使用
environ最后一个char* 指向的是NULL,好让程序判定什么时候该结束
environ的类型是char **
我们用代码测试一下
#include<stdio.h>
#include<stdlib.h>
int main()
{
extern char ** environ;
for(int i=0;environ[i]!=NULL;i++)
{
printf("environ[%d]=%s\n",i,environ[i]);
}
}
运行结果如下
这里我们只展示部分
main函数参数
main函数里面有两个参数,我们一直不明白这两个参数到底有什么用途
int main(int argc,char* argv[])
{
}
argv里面存的都是char*,意思就是argv存的都是字符串,而argc是一个整形,用于记录argv里面有多少个字符串
argv的最后一个元素是NULL,用于程序判断数组是否运行到了结尾,我们来测试一下功能,请看以下代码
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
for(int i=0;i<argc;i++)
{
printf("argv[%d]=%s\n",i,argv[i]);
}
}
我们在命令行执行该程序
命令行会将执行程序后面的参数传给main的参数列表
不管我们添加什么字符都会执行
那么这样又有什么意义呢
我们可以通过这种方式,来为程序增加功能
我们看下面代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char* argv[])
{
for(int i=0;i<argc;i++)
{
if(strcmp(argv[i],"-a")==0)
{
printf("a功能执行中...\n");
}
if(strcmp(argv[i],"-b")==0)
{
printf("b功能执行中...\n");
}
if(strcmp(argv[i],"-c")==0)
{
printf("c功能执行中...\n");
}
}
}
输入不同的选项
我们可以看到进程输出了很多不同的功能
bash 输入一大段字符的时候,会将它们拆分成很多个小的字符存储到main函数的argv数组当中
env参数
int main(int argc,char* argv[],char* env[])
{
}
env 有着和environ相同的功能,存储环境变量,最后一个指针的值为NULL
我们来写一段代码测试一下
int main(int argc,char* argv[],char*env)
{
for(int i=0;env[i]!=NULL;i++)
{
printf("env[%d]:%s\n",i,env[i]);
}
}
运行进程
我们会发现它和environ是一样的输出结果,我们再来测试一下它和environ的地址
我们来写段代码测试一下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char* argv[],char* env[])
{
extern char** environ;
printf("%p\n",environ[0]);
printf("%p\n",env[0]);
}
运行代码
我们发现不但env和environ的值是一样的,他们的地址也是同一份
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc,char* argv[],char* env[])
{
pid_t id=fork();
if(id==0)
{
for(int i=0;i<3;i++)
{
printf("child :env[%d]:%s\n",i,env[i]);
}
}
else
{
for(int i=0;i<3;i++)
{
printf("father:env[%d]:%s\n",i,env[i]);
}
}
sleep(1);
}
运行程序
我们看到子进程和父进程的环境变量是正常使用的,且变量是一致的,所有父进程和子进程共用一套环境变量
在命令行中所有的进程都是bash的子进程,都和bash共用一套环境变量,
bash的环境变量表存在于内存当中,当启动系统时内存会在磁盘中拷贝环境变量到内存中,所以我们修改环境变量表时都是在修改内存中的环境变量表,并不会影响磁盘中的
当我们重启系统时,我们内存重新在磁盘中拷贝环境变量表到内存中,之前对内存的环境变量做的所有更改都不会影响磁盘的环境变量表