加油布鲁斯,你能行的!
一、环境变量PATH中的默认搜索路径1.将程序安装到/usr/bin目录(不带./运行自己写的程序)
1.
我们平时所用的Linux指令虽然也是可执行程序,和我们自己写的二补码程序没哪些两样,这么为何在执行自己的程序的时侯须要加上./,而执行这种系统提供的指令(可执行程序),不须要加上./呢?
2.
要执行一个程序或则指令,必须先找到这个程序。
这也就是为何我们在执行自己写的程序时,要加上./(当前路径),这也许就是为了找到我们所写的程序,而系统指令实际上是系统默认帮我们找到其程序的位置而且执行,假如想不带./的执行自己的程序linux vi,那就须要将程序安装(安装的本质就是拷贝)到/usr/bin目录下边,也就是系统安装指令的路径当中。
但不建议将自己的程序安装到系统默认路径下,由于你的程序是未经过严格测试的,会污染系统的指令池的,所以假如你安装了的话,建议玩完儿以后,再把它删了吧!
2.将程序路径添加到PATH环境变量上面(不带./运行自己写的程序)
1.
为何在/usr/bin路径下的程序,系统就可以找到呢?似乎是由于系统上面存在环境变量PATH,操作系统在启动的时侯,会在的上下文当中定义一个PATH变量,这个变量是全局有效的,假如想要查看内容,可以借助echo而且在PATH后面要加$符号。
2.
在执行系统指令的时侯,系统会默认去PATH环境变量上面的路径,查找我们输入的指令程序,假若找到,系统才会执行这个程序,假如没有找到都会报错commandnotfound,所以假如想要不带./执行自己的程序还有一种办法就是,将自己所写的程序所在的路径添加到环境变量PATH上面。
我们可以任意更改PATH的值,由于只要重新退出登入,PATH环境变量就又会恢复了
3.
export可以拿来将shell变量导出到环境变量PATH上面,导出的时侯须要先将老的环境变量导出进去之后在加上新的路径,否则会出现你的路径直接覆盖掉之前环境变量PATH上面的所有路径的情况,PATH上面的路径下的所有程序都被默认为是系统指令
4.
which指令在底层实现上实际就是从环境变量PATH下的路径当中搜索的,帮助我们查找对应的指令路径,假如我们的程序所在路径也被添加到了PATH中,这么which也就可以查到我们所写的程序了。
5.
我们的环境变量是显存级的,所以在你将自己的路径导出到环境变量PATH以后也只是暂时的,等你退出xshell以后,你的环境变量就又会恢复到默认的样子了
二、环境变量的深度理解1.shell进程和环境变量的关系
1.
在我们登陆shell的时侯,会默认让你当前的shell进程,把对应的bash_profile上面的内容执行一次,就是将环境变量导出到你当前的shell进程当中,环境变量的配置就是通过它在启动的时侯加载到bash当中的,linux在环境变量的配置文件当中就有环境变量的设置,当我们登陆shell的时侯这个环境变量都会load到当前的shell进程当中。
2.
shell做为一种和Linux系统的特殊交互式工具,为用户提供了启动程序、管理文件系统中的文件及运行在Linux上的进程的途径。shell通过解析输入的文本,在内核中执行来达到与系统交互的功能。shell包含了一组内部,通过这种命令可以进行文件管理、程序管理及运行等操作。
3.
不仅在文本命令界面上(or虚拟控制器终端or终端仿真器)通过命令行执行外,可以通过将多个shell命令装入文件中作为程序执行,这种文件就是shell。在Linux系统中有许多不同类型的shell(如ash、tsch、zsh等),它们各自有不同的特点,可以依照需求自行选择。一般Linux发行版本的默认shell都是bashshell(由GNU项目开发的类Unixshell)。
4.
一般我们在执行shell命令的时侯直观的觉得就是命令是直接运行在Linux系统上的,虽然这是个主观的误会,shell本身就是个程序是运行在Linux上的进程,shell命令的执行是在对应的进程内运行的
5.
当用户登录到虚拟终端or终端仿真器上时,才会启动默认的shell程序。用户登录启动哪些样的shell取决于在/etc/passwd用户配置文件中列举的用户默认shell。
6.
Linux系统本身也有一个默认的shell就是/bin/sh,是用于在系统中启动系统shell所指定的默认shell。一般在Linux系统中这个文件是一个符号链接文件,指向/bin/bash这个shell,也可以修改/bin/sh的链接来更换系统默认shell
7.
用户登录终端所启动的shell是一个父shell。在终端的提示符后输入bash命令或其他等效bash命令时会创建一个新的shell程序,这个shell被称为子shell。如下,我们在终端中输入两次bash命令后使用ps--forest查看进程嵌套关系可以看出父shell和子shell的关系
2.环境变量的作用和Linux操作系统的打算工作
1.
无论是我们自己写的程序还是操作系统提早给我们打算好的程序,想要运行都必须先加载到显存上面,由于CPU只能从显存中读取代码和数据,并且这儿有一个潜在的问题,这种程序想要运行,都必须让操作系统先找到这种程序,找到这种程序能够把她们加载到显存上面。
2.
操作系统要找那些程序就必须去特定的路径下边去找那些程序,包括系统自带的指令程序和我们自己所写的程序,操作系统还有可能找头文件,找动态库静态库等等,而且为何你说操作系统能找到这种东西,它能够一定找到呢?操作系统怎样找到这种东西啊?
3.
虽然想要找到这种东西,操作系统须要做好多的打算工作,能够像我们所说的那样轻松,想要找哪些东西就把那种东西找到了,所以操作系统在启动的时侯,他就早已默认从配置文件当中读取了他自己以前把软件安装到了什么路径下,他把安装到什么路径下那些重要信息都记录在配置文件上面,等到OS启动的时侯,把配置文件中的这种信息导出到显存上面,建立出一个显存级变量,这些变量就是环境变量,前面所讲的PATH环境变量就是操作系统在启动命令行例程shell的时侯,将PATH这样的变量导出到shell的上下文当中,当我们执行对应的指令的时侯,我们就必须通过PATH环境变量上面指定的默认的搜索路径去查找对应的可执行程序,所以操作系统为了让我们找到可执行程序,虽然做了好多的打算工作,帮我们定义了许许多多的环境变量,通过环境变量帮助我们做了好多本身我们看不见的工作,除PATH这个环境变量,虽然还有好多好多的其他环境变量,操作系统须要完成其他好多我们忽视掉的工作,这就须要借助那些它自己定义下来的环境变量,这种环境变量都有不同的用途,配色方案,当前路径,主机名,用户名,历史指令记录,默认的shell类型这种都要借助OS他自己定义下来的环境变量去隐式的解决或处理我们看不到的问题和工作。
4.
在不同的使用场景下,要求操作系统在启动shell以后,给我们做命令行解释的时侯,必须预先设置好一批未来shell可能用到的变量,通过这种变量完成我们输入的命令的解释,所以操作系统为了满足不同的应用场景,必须预先在自己的OS内设置一大批的全局变量,这种全局变量虽然就是环境变量!
3.测试环境变量USER
1.
su-虽然是让root重新登陆,这时侯才会以root的身分重新加载好多的东西,把root相关的环境变量全部加载到shell的上下文当中,su仅仅是将身分切换一下,并且当前的路径是没有变化的。
2.
可以看见环境变量USER会随着我们身分的切换不断的更新它的变量值,这也正是USER环境变量所能起到的作用。
4.测试环境变量HOME
1.
HOME环境变量记录当前用户的工作目录在具体的那个路径。
2.
cd的本质虽然就是shell在解析指令时,见到了波浪号,shell都会直接调用环境变量HOME的值
三、环境变量和本地变量的关系(本地变量包含环境变量)1.shell子进程会承继环境变量
1 #include 2 #include 3 #include 4 #define USER "USER" 5 #define MY_ENV "myval" 6 7 8 int main() 9 { 10 char*myenv=getenv(MY_ENV); 11 if(NULL == myenv) 12 { 13 printf("%s: not foundn",MY_ENV); 14 return 1; 15 } 16 printf("%s=%sn",MY_ENV,myenv); 17 18 return 0; 19 }
1.
父进程shell定义的本地变量不会被单进程承继下去,而且父进程的环境变量是会被单进程承继下去的,承继的诱因就是为了满足不同的应用场景,由于许多系统指令(ls、whoami、pwd、which、su-)还会涉及到使用环境变量,所以这种指令(子进程)必须承继父进程bash的环境变量,以满足不同的使用场景。
所以环境变量是具有全局性的,由于无论是父进程还是子进程都有环境变量,子进程的环境变量是从父进程承继得来的。
2.
本地变量只会在当前进程bash内部有效linux启动进程命令,由于它不会被承继下去,具有局部性。
2.显示本地变量和环境变量的指令
1.
set指令可以显示shell中的环境变量和非环境变量
2.
set显示下来的变量巨多,由于shell本地变量包括了环境变量
下边的本地变量>就是指令续行时侯的提示符
3.env可以显示所有的环境变量
3.导环境变量+取消本地变量
export MYVAL="youcanseeme" unset MYVAL
1.
导出环境变量可以先在命令行定义本地变量,之后导成环境变量,也可以两个步骤同时进行,取消环境变量或本地变量可以通过unset指令来操作。
2.
因为自己定义的环境变量默认就是字符串,所以在定义的时侯既可以带上双冒号,也可以不带双冒号,但若果出现定义的环境变量带空格的话,就必须带上双冒号了,所以还是建议在定义的时侯带上空格
4.为何ls显示文件的时侯不用带./呢?(shell会维护环境变量)
1.
shell会维护环境变量的值,就例如我们会不停的切换路径,这么环境变量PWD的值都会随时被shell修改为当前路径,所以ls在作为子进程运行的时侯,承继PWD的值以后,ls就可以理所应该的显示下来当前的路径是在那儿。
2.
下边我们也可以自己用C语言程序的运行来获取当前路径,借助shell实时维护环境变量PWD的特点来完成。
1 #include 2 #include 3 #include 4 #define USER "USER" 5 #define MY_ENV "myval" 6 #define MYPWD "PWD" 7 8 int main() 9 { 10 printf("%sn",getenv(MYPWD)); 11 }
5.环境变量的配置文件详述
四、命令行参数表和环境变量表1.命令行参数表
1.
在main函数中实际上有隐藏的参数,只不过我们平时不使用这种参数,由于我们平时用不着,在系统编程中,使用这种参数是比较常见的,而且main会被一个叫START_UP的函数调用,START_UP函数在你的程序加载到显存的时侯,被操作系统调用,参数实际上就是我们的命令行类库bash也就是父进程传递的,我们只须要在命令行上写指令就可以了,shell在解释我们的指令时,才会给main函数传参了。
1 #include 2 #include 3 #include 4 #define USER "USER" 5 #define MY_ENV "myval" 6 #define MYPWD "PWD" 7 #include 8 9 10 11 int main(int argc ,char* argv[]) 12 { 13 14 for(int i=0;i<a style='color:#0000CC;font-size:16px;' rgc;i++) 15 { 16 printf("argv[%d]->%sn",i,argv[i]); 17 } 18 19 }
2.
在命令行中运行程序的时侯,实际上可以添加命令行参数,shell在解释这种指令的时侯,还会给main函数传参
3.
main函数中的第一个参数是命令行中运行程序的时侯字符串的个数,以空格为分隔符,例如前面运行时-a-b-c等,实际上是三个字符串,./mycmd也是一个字符串,所以argc代表的就是字符串的个数,argv表针链表中的表针,指向的就是这种字符串,通过程序运行结果和代码,可以证明这个推论,argv字段中复印下来的值实际上就是那些字符串,所以main函数中的第二个参数就是命令行参数表,表中的表针指向命令行中的所有字符串。
这么他有哪些意义呢?
4.
系统指令虽然就是C语言写的程序,这么它在带指令运行的时侯,也能实现不同的功能,这是如何做到的呢?实际上在实现的代码中的main函数就是须要argc、argv这样的参数实现的
下边我们就浅显的实现一个不同选项拥有不同功能的进程。
int main(int argc ,char* argv[]) 12 { 13 14 if(strcmp("-a",argv[1]) == 0) 15 { 16 printf("功能an"); 17 } 18 19 if(strcmp("-b",argv[1]) == 0) 20 { 21 printf("功能bn"); 22 } 23 if(strcmp("-c",argv[1]) == 0) 24 { 25 printf("功能cn"); 26 } 27 28 if(strcmp("-ac",argv[1]) == 0) 29 { 30 printf("功能acn"); 31 } 32 if(strcmp("-bc",argv[1]) == 0) 33 { 34 printf("功能bcn"); 35 } 36 if(strcmp("-ab",argv[1]) == 0) 37 { 38 printf("功能abn"); 39 } 40 if(strcmp("-abc",argv[1]) == 0) 41 { 42 printf("功能abcn"); 43 } 44 }
5.所以命令行参数最大的意义就是,通过不同的参数(也就是执行时携带的选项)促使进程拥有不同的功能。
6.
在windows下的命令提示符当中,我们也可以通过不同的命令行参数,来促使进程实现不同的功能,比如下边的死机指令,可以设置死机时间,也可以取消死机,选择死机,通过-t、-a、-s等参数实现。
2.子进程中三种获取环境变量的方法2.1通过系统调用获取环境变量(获取指定的环境变量内容)
1.
通过getenv()系统调用就可以获得环境变量USER的值是哪些
1 #include 2 #include 3 #include 4 #define USER "USER" 5 6 7 8 int main() 9 { W> 10 char*who = getenv(USER); 11 printf("USER:%sn",who); 12 return 0; 13 }
2.
sudo的本质虽然就是将环境变量USER由普通用户改成root用户qq for linux,这时侯个别不容许普通用户所做的行为,通过root用户的身分就可以做了。
下边代码以浅显的方法解释了我们平时以普通身分进行个别操作时,遇见的权限拒绝的原理,虽然在真正的过程当中是须要用到getenv()和一些文件属性获取的系统调用stat(),通过这种系统调用,来查看你是否拥有对应操作的权限。
3.stat获取文件属性,这一系统调用插口,旁边的博文会详尽讲解。
1 #include 2 #include 3 #include 4 #define USER "USER" 5 6 7 8 int main() 9 { 10 char*who = getenv(USER); 11 if(strcmp(who,"root")==0) 12 { 13 printf("USER:%sn",who); 14 15 } 16 else 17 { 18 printf("permission denied!n"); 19 } 20 21 return 0; 22 }
2.2环境变量表(获取所有的环境变量名和内容)
W> 11 int main(int argc ,char* argv[],char* env[]) 12 { 13 14 for(int i=0; env[i]; i++) 15 { 16 printf("env[%d]-->%sn",i,env[i]); 17 } 18 19 }
1.
可以看见,通过main函数的第三个参数,子进程也可以获得所有的环境变量。这也是子进程承继shell环境变量的一种形式。
2.
每位进程就会被shell传一个环境表,环境表是一个字符表针链表,每位表针指向一个以斜杠0结尾的环境变量字符串
2.3第三方表针变量environ(获取所有的环境变量名和内容)
1.
C语言默认提供了一个第三方表针变量称作environ,在调用main的时侯,实际上系统就把environ这个变量作为main的第三个参数传给main函数了,这儿涉及到C语言中链表传参的问题,environ就相当于表针链表env[]的另一个链表名,environ指向的就是env链表的第一个元素,按照形参名代表首元素地址可知,environ似乎就是env的另一个链表名。
2.
environ是在编译好c或c++程序以后,系统默认初始化好的一个全局的二级表针,指向env字段的第一个元素,由于environ[i]=*(environ+i),所以另一种获取环境变量的方法如下
1 #include 2 #include 3 #include 4 5 6 int main() 7 { 8 9 extern char** environ; 10 for(int i=0; environ[i]; i++) 11 { 12 printf("environ[%d]-->%sn",i,environ[i]); 13 } 14 15 }
五、通过系统调用修改或降低环境变量
后面是通过命令行式的export指令来降低环境变量,我们也可以通过系统调用putenv()来修改或降低环境变量linux启动进程命令,这个系统调用放在前面的博文来进行详尽的讲解。
本文原创地址://q13zd.cn/jyblsnnxdhjb.html编辑:刘遄,审核员:暂无