大家好,我是苏貝,本篇博客带大家了解Linux进程(6):环境变量,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
目录
- (A)PATH
- (B)环境变量对应的配置文件
- (C)更多的环境变量
- (D)环境变量操作
- [(E)理解环境变量 系统](#(E)理解环境变量 系统)
-
- [1. 用代码拿到环境变量](#1. 用代码拿到环境变量)
- [2. 环境变量再理解](#2. 环境变量再理解)
- [3. 本地变量](#3. 本地变量)
(A)PATH
我们知道,在命令行中输入的系统指令和我们自己写的程序最后都会成为进程,但为什么系统指令前面不需要绝对/相对路径,而我们自己写的程序需要呢?
因为在Linux中,存在一些全局的设置,它们告诉命令行解释器,应该去哪些路径下寻找可执行程序
下面以环境变量PATH为例
先打印环境变量PATH的内容
注意:PATH前要加$
PATH的内容中有很多路径,它们以: (冒号)作为分隔符
PATH中的路径有什么用呢?
- bash在执行命令的时候,需要先找到命令才能在未来将命令加载,那在哪找命令呢?如果命令前面没加绝对/相对路径,那么bash就会在PATH里的路径中查找,如果找到了,就加载;没找到,就会报错。
- 执行which命令时,which也是在PATH的路径里查找
现在,我想让我们自己写的程序和系统指令一样,前面不需要绝对/相对路径即可执行,有什么办法呢?有2种方法
方法1:将程序拷贝到PATH内容的路径下(不建议)
注意:此时需要用root管理员身份进行拷贝(直接转换成root身份或者sudo提权)(相当于将myprocess程序安装到Linux系统中)
我们非常不建议这种写法,所以现在我们将myprocess程序从/usr/bin路径下删除(相当于卸载程序)
当我们直接在命令行输入myprocess,bash报错,表明myprocess确实从/usr/bin路径下删除了
方法2:将程序的当前路径添加到PATH中
程序的当前路径为Linux_code/lesson_14,先直接将PATH赋值为Linux_code/lesson_14,所以PATH原先的内容完全被覆盖,只有Linux_code/lesson_14。此时再使用ls等系统命令就会报错,因为它们都在/usr/bin目录下,而/usr/bin不在环境变量PATH中
现在关掉该终端,重新打开一个终端,再来查看PATH的内容
我们发现,PATH的内容又变回原来的了,这是为什么?
系统中很多的配置,在我们登录Linux系统的时候,已经被加载到了bash进程中(内存里)。最开始的环境变量不是在内存中,而是在系统的对应的配置文件中。当我们登录Linux系统时,环境变量对应的配置文件被加载到了bash进程中,所以默认我们查到的环境变量是内存级的,我们对环境变量PATH的修改也是在内存里修改,并不影响环境变量对应的配置文件。因此当我们关闭终端后,bash进程被杀掉,bash占据的内存空间被释放,再次打开终端,bash进程重新加载环境变量对应的配置文件,所以PATH的内容变回原来的了
虽然如此,但我还是不想在我们自己写的程序前面加绝对/相对路径,不能用我们上面的直接赋值的方法,怎么办?
PATH=$PATH: /home/zy/Linux_code/lesson_14,中间用: (冒号)分隔
下一个问题:我们能否将PATH的内容永久修改呢?可以,根据我们上面的解释,只需要修改对应的配置文件。那环境变量对应的配置文件在哪里?
(B)环境变量对应的配置文件
先将当前目录变成家目录(cd ~),再执行ls -al,列出家目录的所有文件的详细信息,包括以.开头的隐藏文件
找到.bash_profile和.bashrc文件,这就是环境变量对应的配置文件。打开2个文件
现在将myprocess当前路径加入到配置文件中PATH里即可
将配置文件修改回去
(C)更多的环境变量
1.环境变量HOME:家目录所在的环境变量
普通用户的家目录(以普通用户zy为例)是/home/zy,所以它的环境变量HOME=/home/zy
root的家目录是/root,所以它的环境变量HOME=/root
2.环境变量PWD
系统怎么知道我们当前在哪个目录下呢?
系统有个会变化的环境变量PWD,它会随着我们路径的变化,将当前路径动态地记录在PWD中
3.环境变量SHELL
shell是命令行解释器,常见的Shell工具包括:sh、bash、csh、tcsh、ash 等,所以我们怎么知道当前我们启动的是哪个呢?
所以我们的shell是bash
4.环境变量HISTSIZE:记录的历史命令的个数
在命令行中,我们可以通过按上下键翻到我们的历史命令,能上翻就表明我们曾经的命令是被Linux系统记录下来的,但系统不能一直记录吧,所以用HISTSIZE表示Linux系统能记录最新的多少个历史命令
我们可以用history命令来查看这1000条历史命令
5.env:查看所有的环境变量
HOSTNAME是主机名
(D)环境变量操作
env和echo之前有介绍过,这里不再赘述
export name=value:导出环境变量,环境变量名为name,值为value
现导出一个叫THIS_IS_MY_ENV的环境变量,值为hello
关掉终端后,环境变量THIS_IS_MY_ENV还存在吗?
不存在,因为这是在内存中导出了新的环境变量,并没有添加到对应的配置文件中
unset name:取消环境变量
本地变量
env查不到,所以asdf不是环境变量,但又能通过echo $查看内容,叫这样的为本地变量
(E)理解环境变量 系统
1. 用代码拿到环境变量
修改.c文件
先不要管environ是什么意思,我们目前只知道它的类型是char**。指向程序
我们发现,这就是我们的环境变量。在命令行参数中,我们讲过,父进程的数据,默认能被子进程看到并访问。对于./myprocess进程,其父进程是bash,且在Linux登录时,环境变量对应的配置文件被加载到了bash进程中,所以./myprocess进程能看到并访问bash的数据(环境变量)是可以理解的。
环境变量可是很多的,bash内部是如何组织的呢?
bash进程启动的时候,会从操作系统的配置文件中形成char* env[ ],它是一个指针数组,元素类型为char*,即元素指向某个字符或字符串。事实上,env数组的元素就指向环境变量,数组的最后一个元素指向NULL
你有没有发现,env数组和我们在命令行参数中讲的argv数组很像,都是指针数组,元素类型都是char*,最后一个元素都指向NULL...,所以main函数其实也可以有3个参数,分别是int argc,char* argv[ ]和char* env[ ]
因此main函数可以没有参数,也可以有2或3个参数
事实上,bash进程在启动的时候,默认会给子进程2张表:argv[ ]命令行参数表(用户从命令行中输入),env[ ]环境变量表(从OS的配置文件中来)。bash会通过各种方式将它们交给子进程
environ就是指向env数组
其实我们还可以用env数组来打印出环境变量
修改.c文件
上面的两种方法(char** environ和char* env[ ] )都是将环境变量全部打印出来,那如果我只想打印某个环境变量(如PATH),怎么办?
用getenv函数
先用man getenv命令查看getenv函数:头文件是<stdlib.h>,参数是环境变量名(如PATH),返回值类型是char*
修改.c文件
所以想要用代码打印环境变量,有3种方法
extern char** environ
通过main函数的参数:char* env[ ]
getenv函数
2. 环境变量再理解
环境变量具有系统级的全局属性
命令行中启动的程序,都会变成进程,且都是bash的子进程。那如果bash的子进程1再次fork形成子进程2,那子进程2能否看到bash的环境变量呢?
可以,因为环境变量具有系统级的全局属性,环境变量本身会被子进程继承下去。也就是说,如果将bash进程作为树的根节点,bash的子进程作为根节点的孩子节点,bash的子进程的子进程作为bash的子进程的孩子节点......,那么这整棵树都可以看见并访问bash进程的环境变量
内建命令:由bash亲自执行的命令
在Linux系统中,有80%的命令都是bash创建子进程执行的,如:ls,mkdir,cp等;也有一些是由bash亲自执行的命令,叫内建命令,如:export,echo
现在证明export是内建命令
先导出新的环境变量myval并赋值,在bash里面能找到myval
假如export是由bash创建子进程执行的,那么myval就不应该被bash看到,因为父进程不会看到被子进程修改的数据。所以export是内建命令
还能通过下面的方法证明:
先将环境变量PATH的内容置为空,而bash在执行普通命令时,需要先在PATH内容的路径下查找,只有找到了才能执行命令。现在PATH的内容为空,所以bash在PATH里没有找到ls,touch,cd等命令,所以这些命令都不能被执行。但是bash可以执行echo和export命令,因此它们是内建命令
3. 本地变量
本地变量只有在本bash内部才有效,无法被子进程继承下去。只有将本地变量导成环境变量,才能被子进程继承
证明:
新建一个本地变量AAA并赋值为111
上图表明本地变量AAA不被认为是环境变量,所以不在bash的env中。但AAA还是在bash内部的。同样能证明,echo是内建命令,否则它不能访问只在bash内部才有效的AAA
修改.c文件
执行程序后,path=NULL,所以子进程不能看见并访问bash的本地变量
将本地变量导出成环境变量
此时AAA既在bash的env中,也可以被子进程看见并访问
好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️