基础环境变量一般是操作系统中用来指定操作系统运行环境的一些参数在系统中具有全局特性还有某些特殊用途。我们先来认识一个环境变量PATH通过它我们就能大致了解环境变量的概念与特性。我们知道我们输入的命令都是先由命令行解释器bash处理的绝大多数指令都有对应的可执行文件执行这些指令的本质就是让bash通过路径找到文件并运行。为什么执行我们的文件需要加上路径比如 ./test 或 /home/uesr1/test 等而执行指令却不用呢事实上如果我们能知道 ls 的可执行文件放在哪我们也可以用这种路径访问的方式运行 ls 它就在路径 /usr/bin 下。使用/usr/bin/ls 也能执行ls指令各种选项也可以正常使用。那么bash是如何找到 ls 的可执行文件在哪的呢答案是通过环境变量PATH。如果想查看环境变量的具体内容可以使用echo $[环境变量]我们可以看到里面有多个路径如果bash在这些路径下都没有找到要运行的指令就会发出我们熟悉的报错。PATH也是可以修改的使用命令 PATH$PATH:[路径] 就能在其末尾添加路径这样就可以直接运行对应路径下的文件。不过通过这种方式作出的修改在重新登录后就会重置。或者我们也可以反过来把代码的可执行文件拷贝到这些路径下这样就能像指令一样不用 ./ 直接运行需要root权限但是不建议这么做。环境变量本质就是一些字符串字符串里面是一些bash经常需要用到的信息比如家目录、用户名、配色方案、当前工作路径等。bash创建时会从系统的相关配置文件中读取环境变量通过申请内存空间来存储这些环境变量用指针数组也是向内存申请来的空间存储指向各个空间的指针。这个指针数组就是环境变量表bash就是通过它来使用各个环境变量。 在家目录下使用ls -al 或者直接 ll 就可以查到配置文件下面的 .bashrc 就是配置文件不同发行版本的Linux系统可能有所不同。在配置文件.bashrc中修改PATH就可以实现永久更改即使重新登录也不会被重置。直接在文件末尾添加命令 export PATH$PATH:[路径] 即可如下。接下来我们继续认识其它一些常见的环境变量直接输入指令env就可以查看所有的环境变量下面是常见环境变量的解释。不同版本的Linux可能有所差异。HOME 家目录USER 当前用户的用户名LOGNAME 登录的用户的用户名一般和USER相同HISTSIZE 记录历史命令条数的上限1000就是最多记录之前的1000条命令HOSTNAME 当前主机的主机名LS_COLORS 配色方案LANG 编码格式PWD 当前工作路径SSH_TTY 是当前终端设备名OLDPWD 是上一次所在的路径使用 cd - 返回上一次所在的路径就是通过它实现的。修改已有的环境变量很简单使用前面提到过的命令 [环境变量]$[内容] 即可。我们也可以新定义环境变量或取消已有的环境变量。export [变量名][内容] 新增环境变量unset [变量名] 取消环境变量在程序中也可以查看环境变量事实上进程地址空间中有一个区域叫做环境变量块是栈和堆之间的共享区的一部分里面存储的就是该进程的环境变量。进程的PCB中自然也有指向这个区域的指针。由此可见包括bash在内的每个进程都有自己的环境变量初始时都是继承自父进程我们之后在程序中查看的环境变量全都来自这个环境变量块。比较特殊的是bash为了提升效率自己还另外维护了一张环境变量表其次bash的环境变量除了继承自父进程还会从配置文件中读取。命令行参数不过在正式开始用代码查看环境变量之前我们需要补充一下命令行参数的知识顺便了解bash中的另一张表——命令行参数表。我们知道C语言的main函数可以接收两个参数int main(int argc,char* argv[])其中argv就是用于接收各个命令行参数的它以NULL结尾。当我们在使用命令./code ac b 运行可执行文件code时这一行命令会被bash按照空格划分成三段字符串分别是./code 、ac和b然后先传到bash中的命令行参数表再传给main函数的参数argv这些字符串就是命令行参数。argc则是命令行参数的个数也就是argv中有效元素的个数。通过这两个参数可以实现程序的不同子功能。我们用各种选项使用指令的不同功能就是这样实现的通过参数argv来查看附带了什么选项从而运行对应的功能。#includestdio.h #includeunistd.h int main(int argc,char* argv[]) { if(argc1) printf(默认功能已启用\n); else for(int i1;iargc;i){ printf(功能 %s 已启用\n,argv[i]); } return 0; }不难看出bash中的命令行参数表就是用于临时存储输入的命令行参数。那么为什么命令行参数要先传给bash呢不要忘记了我们只是输入了命令真正去运行可执行文件的是bash。只有将文件运行起来才会调用main函数。需要先让bash通过第一个命令行参数./code找到相应的可执行文件并运行才能将所有的命令行参数传给argv。所以命令行参数自然是要先交给bash。上面的命令中是直接给出了可执行文件code的路径如果是像 ls 之类的指令bash则会通过环境变量表中的PATH寻找对应的可执行文件。获取环境变量接下来我们来看程序中如何获取环境变量。使用main函数的第三个参数char* envp[]可以查看继承自父进程bash的环境变量和argv一样以NULL结尾。#includestdio.h #includeunistd.h int main(int argc,char* argv[],char* envp[]) { (void)argc; (void)argv; int i0; char* curenvp[0]; while(cur){ printf(%s\n,cur); i; curenvp[i]; } return 0; }这里提一点编译器会自动识别main()函数使用了几个参数从而确定在调用main函数时要传入几个参数。如果后面没有使用这些参数可能会警告甚至报错。可以将不使用的参数强转成void类型通过这种特殊的使用方式来避免报错。下面是部分运行结果。也可以使用函数char* getenv(const char* name) 根据传入的环境变量名获取环境变量的内容需要头文件stdlib.h。getenv获取的是当前进程的环境变量。通过获取环境变量USER还可以让代码只有特定用户能正常运行如下。#includestdio.h #includestdlib.h #includestring.h int main() { const char* usergetenv(USER); if(userNULL) return 1; else if(strcmp(user,tester)0) printf(猿神启动\n); else printf(你无权使用\n); return 0; }最后还可以使用头文件unistd.h中的全局变量environ它是以NULL结尾的指针数组数组中的指针指向的就是环境变量块中的各个环境变量通过它可以查看当前进程全部的环境变量。前面的getenv就是用environ查找的环境变量。由于environ是外部文件的变量需要先用extern声明后才能使用。#includestdio.h #includeunistd.h extern char** environ; int main(){ int i0; char* curenviron[0]; while(cur){ printf(%s\n,cur); i; curenviron[i]; } return 0; }在程序中也可以为当前进程添加环境变量调用putenv函数即可需要头文件stdlib.h。定义如下。int putenv(char *string);如果添加的环境变量已经存在则会修改该环境变量的内容。putenv新增环境变量时会在environ中添加指向新环境变量的指针但不会在main函数的参数envp中添加毕竟envp只是个局部变量甚至都不一定存在。所以envp只能查看继承自父进程的部分新增的环境变量查看不了。putenv的具体使用如下定义环境变量的字符串不能被销毁最好定义成全局的。#includestdio.h #includestdlib.h char* tempmy_new_keyconfidence; int main(){ const char* enmy_new_key; putenv(temp); printf(my new key is %s\n,getenv(en)); return 0; }不过在程序中通过putenv添加的环境变量只有该进程及其子进程能使用所有运行中的程序都是进程它的父进程是用不了的包括bash。在命令行中还可以用一种特殊的方式添加环境变量那就是将已有的本地变量转化为环境变量。在命令行中直接定义的变量就是本地变量比如count1、my_keypatience等。本地变量主要的用途就是临时数据的存储与循环的控制如下它不会被子进程继承只在bash内使用。使用set就可以查看所有变量包括环境变量和本地变量。前面使用的指令export就可以把本地变量改成环境变量。但我们知道进程之间具有独立性进程之间不能相互修改数据export应该是不能修改环境变量的因为环境变量是进程bash中的数据那它是如何做到的呢其实export是内建命令执行内建命令时不需要创建子进程而是由bash亲自执行。常见的pwd和cd也是内建命令。执行这些命令是由bash自己调用函数或系统调用接口。如下将本地变量改为环境变量。