目录
②没有命令行参数:getenv:根据环境变量的名字获得环境变量的内容
unset 本地变量/环境变量名:从shell上下文简单的移除。
1.环境变量前言认识
谈及环境变量可能大家有些陌生,实际上我们时不时跟环境变量还是有所接触,比如1我们在下载编译器的时候,有时就会有叫我们安装环境变量这样的动作,我们的环境变量在我们的windows电脑中,我们可以在属性中搜索
有自己的环境变量,和系统的环境变量,,有用户自己的就用用户自己的,没有就用系统的,
那么我们就可以知道未来我们在linux中进行环境变量的配置的时候,可能需要普通用户的环境变量,而用户的环境变量,,要么是自己配置的,要么是继承系统的。我们安装javah或者python有时都会叫我们配置一下path.一般是填写路径。
解释一下:
一般安装软件都是需要有可执行程序的,我们在cmd中执行一些命令,有些就直接可以执行,而有些不可以,这是因为我们要执行一个命令的前提是要先找到这个命令,如果没有配置过path这个环境变量,一般是找不到的,就需要将软件的路径配置到环境变量中,我们执行命令的时候就不用输入路径。
我们配置环境变量就是为了让系统找到我们的可执行程序,动静态库等等。这和我们的linux中的差不多,我们先来看一下和环境变量这个比较接近的一个东西,main参数
1.main参数----命令行参数
我们写main函数的时候,它带参数吗?
答案是带的,
第二个参数:是一个指针数组,指向的是一个一个的字符串。我们以前都没有使用过这,今天可以来做一下测试。
第一个参数是数组元素的个数
我们看到这样的结果不必过于诧异,我们来进行慢慢梳理
我们的bash在这里给我们做了一个 输入的动作,输出我们的命令行。接下来bash定义了一个字符数组,用户输入指令,bash将指令看做一个字符或者字符串存入数组中,看似我们输入以空格分割了,实际上我们输入的是一个大字符串,这个字符串被bash读到,bash按照空格作为分隔符,将其转换为小的字符串,将字符串一变多,我们目前就认为bash为了保存这些小串给我们维护了一个char* 类型的数组,以NULL结尾,定义一个count来记录小串的数量,接下来执行程序,将数组和count按照一定的方式(这里不做探讨)传给我们的main函数
我们传入整个这个表可以成为命令行参数表,整个表结尾必须以NULl结尾。所以我们的代码也可以这样写:
利用最后一个指针为空作为循环结束条件
将我们的字符串一变多,但是为什么要这么做呢?
为什么将指令一变多传给程序?
假设,要求一个程序实现三种不同的功能
我们运行看一下:
我们可以通过不同的选项,让我们的程序执行不同的功能, 那么这个程序的运行像什么相信大家已经发现了:
所以ls这样的命令和其他命令,大部分都是c/c++写的,这也就是我们的指令可以传递不同的选项, 而且可以根据不同的选项执行不同的功能,本质就是:我们的所有的选项,最后都会传给指令中main函数对应的argc argv,完成不同的功能,所以选项的本质就叫做命令行参数。
在我们的windows中也是一样的:
实现一个基于命令行的计算器:
所以我们的命令行参数,是Linux指令选项的基础。(java python 等都是有命令行参数的,因为这个功能并不是c/c++特有,同一个程序可以使用内部不同的子功能,几乎所有的语言都有这样的刚性需求)
2.环境变量---认识,初步找一下简单的环境变量,用一下
环境变量在构成上和参数选择上和命令行参数是非常相似的。我们进上述经验移动下来理解环境变量。
环境变量:不是一个而是一堆,这些变量之间彼此其实没有关系,环境变量很多,有的记录当前是谁,有的记录当前路径,主机名是多少。环境变量是系统内置的,具有特殊用途的变量。在这里这种变量是一种说法,定义变量的本质,是开辟空间,为了方便表述这块空间,给这块空间取了名字,这是在语言上的定义。那么世界上是不是只能通过语言来开辟空间呢,这是不一定的,开辟空间不一定是编译,写代码的时候定义,在运行期间我们的程序也可以开辟空间,操作系统/bash是用C语言写的程序,是可以自己开辟空间的,系统的环境变量,本质就是系统自己开辟的空间,保存名称内容,为了方便表述,我们称之为环境变量。
见一下环境变量:常见的:
对于我们自己写的程序,我们在运行时,可以./文件名或者直接用我们可执行文件的绝对路径都是可以执行的:
但是当我们仅仅只输入我们程序的名字时:
操作系统说找不到这个程序,执行程序的前提是找到这个程序。
但是,我们说指令也是程序,我们在运行我们的系统指令也就是我们的系统自己的程序时既没有带./也没有带路径,但是可以运行:
原因就是存在一个全局的系统变量:PATH
如何查看这个系统环境变量: echo $PATH
在我们的系统里面,有一块内存空间里面保存字符串,将这个空间命名weiPATH,无论执行什么命令都到这个路径下面去搜索,这个路径由无数个子路径构成,以冒号为分割符号,每一个路径都是系统默认的搜索路径,只不过我们的ls等就在我们的bin目录下,可以找到,但是我们自己的程序没有在bin里面就没有办法。
如果将我们的程序拷贝到上述路径中的任何一个:
就可以直接运行了。 这个就相当于将自己的软件安装到系统里面了。我们写的东西会污染我们的系统命令池,一般不建议写进去,将其移除:
为了避免污染我们的系统命令池子,我们一般将我们程序的绝对路径添加到PATH中;具体做法:
PATH = 当前文件的绝对路径:$PATH回车
环境变量PATH被覆盖及解决办法:
PATH = 当前文件的绝对路径直接回车就被覆盖了
由于是内存级别的,我们只用重新登录启动,系统就会重新为用户初始化就OK了,得以恢复。
第二,我们刚启动系统的时候,系统是如何知道我们在那个位置的呢,我们使用pwd指令可以查出我们当前所在的位置是因为,我们的系统里面有一个PWD的环境变量,当我们用户的位置改变的时候,PWD的内容也会随着刷新,我们使用pwd命令的本质就是这个指令去读取:PWD这个环境变量里面的内容。
whoami 指令也是因为存在一个USER的环境变量,才知道当前的用户是谁:
记录用户名
我们每次登陆我们的操作系统,默认处于家目录,操作系统也是因为存在一个HOME的环境变量,记录就是当前指定的用户的家目录
env命令一次性查看当前系统中的所有环境变量:家目录、用户名、用的shell、可以保存的指令等等等等
、
当用户启动时,用户的周边信息保存在了环境变量和维护在内存中,所以操作系统在执行的时候才会认识我们是谁。 用户进入这个系统提前给用户准备好的变量叫做环境变量。(不仅仅语言可以创建变量,系统级别也可以,创建变量的本质就是空间开辟)
3.环境变量--挖掘其特性--引入环境变量的命令行操作
env 查看全部变量
echo $变量名 查看单个变量
创建一个环境变量:
export 变量名=值
环境变量本质是什么,该怎么理解:
mian函数除了两个参数,实际上还可以带一个参数
结论;操作系统会将环境变量以main函数的参数的形式传递给我们的程序或者叫做进程
说明:我们的程序运行会变成进程,变成程序前首先从main函数开始运行, main函数也有参数,一般由父进程来传递参数,在当前是bash,在bash给我们构建命令行的时候,会构造出命令行参数这张表和命令行参数个数交给mian函数
同理bash在自己对应的代码中,也同时内置一张这样的表:
有了这张表后,我们自己程序在运行的时候,bash将这张表的起始地址1传给main函数,我们的子进程也就得到了父进程的环境变量,也就是说环境变量是可以被子进程继承下去的。(方式1)
所以bash在创建子进程的时候会维护两张表一张命令行参数表,一张就是环境变量表
然后就可以向main函数传参,所以我们的程序才可以根据不同的指令执行不同的工作,同时提供环境变量,供我们后续操作。
然后我们再创建一个孙子进程呢?
环境变量具有全局属性:环境变量会被所有子进程包括孙子进程进行继承
现在我们创建一个环境变量:
然后运行一个我们自己的程序:
我的进程以及子进程都可以继承这个环境变量:
所以让所有的进程以环境变量的方式进行信息传递。
4.环境变量---代码获取和设置环境变量
获取环境变量方式:①命令行参数使用继承的方式
②没有命令行参数:getenv:根据环境变量的名字获得环境变量的内容
获取成功,返回值是char*,获取失败返回值是NULL
int main()
135 {
136
137 const char* username = getenv("USER");
138 if(username)
139 printf("username:%s\n",username);
140 else
141 {
142 printf("None\n");
143 }
144 return 0;
145 }
146
用户为什么要使用环境变量,PATH确实需要,因为运行程序需要找到,那么
其他环境变量的意义
使用环境变量来做身份识别
int main()
135 {
136
137 const char* username = getenv("USER");
138 if(strcmp(username,"user-110")==0)
139 printf("username:%s:欢迎主人回家,现在开始启动程序\n",username);
140 else
141 {
142 printf("对不起,您没有权限开启服务,请尽快离开\n");
143 }
144 return 0;
145 }
146
③.environ 指向环境变量表的指针
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
#include<stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 extern char** environ;//声明不能赋值
6 //environ
7 int i = 0;
8 for(i = 0;environ[i];i++)
9 {
W> 10 printf("environ[%d]:%s\n",i,environ);
11 }
12
13
14 return 0;
15
16 }
~
除了环境变量还有本地变量的概念:
5.本地变量
我们用查询环境变量的方式来查询一下我们定义的本地变量,是查找不到的
使用set命令回车
将当前系统中所有的变量显示出来,包括环境变量和本地变量。
这样看我们的环境变量和我们定义的本地变量好像没有什么不同,接下来我们编写这样一段代码:
#include<stdlib.h>
19 int main()
20 {
21 const char * myenv= getenv("testvalue");
22 if(myenv == NULL)
23 {
24 printf("getenv get null\n");
25 }
26 else{
27 printf("testnalue=%s\n",myenv);
28 }
29
30
31 return 0;
32 }
~
修改一下代码:将变量名字换成我们的本地变量
#include<stdlib.h>
19 int main()
20 {
21 const char * myenv= getenv("a");
22 if(myenv == NULL)
23 {
24 printf("getenv get null\n");
25 }
26 else{
27 printf("testnalue=%s\n",myenv);
28 }
29
30
31 return 0;
32 }
解释:当我们的程序运行起来,变成bash的一个子进程,由于环境变量也是数据可以被子进程继承,所以可以通过getenv函数去访问到。 但是本地变量只在bash内部有效,不能被子进程继承。所以本地变量不是环境变量。
变量的存在支撑了一门语言,我们能够在命令行定义变量也是说明支持其成为语言也就是我们的shell脚本语言
取消环境变量或者本地变量:
unset 本地变量/环境变量名:从shell上下文简单的移除。
就无了
我们说bash是一个进程,所有的环境变量是保存在bash的上下文中,是内存级别的数据,当我们关闭系统,环境变量也就销毁了,当我们重新登录,环境变量又有了,这是因为环境变量就像一份配置文件被放在磁盘的特定位置,当我们的bash启动时,就会去读取这个配置文件,形成环境变量表,变成内存级别的数据。那我们就来看看这些环境变量从哪里拿到:
6.查看环境变量来源
我们来到家目录:找到一个隐藏文件.bashprofile
每一个用户的家目录里面都有这个文件,我们vim打开:
这个脚本就是用于导入环境变量的。如果我们要自己导入环境变量,不要修改系统的环境脚本,我们自己在后面exprot后,就是模仿path的导入就可以,然后重新登录就可以使用
然后我们再来看一下具体的shell脚本:在我们的这个路径下
所有的环境变量就来自于这里。
所以,每一个用户都有自己的bashfile,都有一套自己的环境变量,所以我们在配置vim的时候只会影响我们自己,也就是为什么我们登录时某认处于家目录。我们需要在自己的家目录下读到自己的环境变量脚本。
7.总结
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但 是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
PATH : 指定命令的搜索路径HOME : 指定用户的主工作目录 ( 即用户登陆到 Linux 系统中时 , 默认的目录 )SHELL : 当前 Shell, 它的值通常是 /bin/bash 。 echo $NAME //NAME: 你的环境变量名称可查看环境变量 1. echo: 显示某个环境变量值2. export: 设置一个新的环境变量3. env: 显示所有环境变量4. unset: 清除环境变量5. set: 显示本地定义的 shell 变量和环境变量