目录
Linux环境变量
基本概念
常见环境变量
查看环境变量方法
测试PATH
测试HOME
和环境变量相关的命令
环境变量的组织方式
通过代码如何获取环境变量
命令行参数
命令行第三个参数
通过第三方变量environ获取
通过系统调用获取或设置环境变量
编辑环境变量通常是具有全局属性的
Linux环境变量
基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
常见环境变量
- PATH : 指定命令的搜索路径
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
- SHELL : 当前Shell,它的值通常是/bin/bash。
查看环境变量方法
echo $NAME //NAME:你的环境变量名称
查看环境变量PATH:
测试PATH
下面我们来看一个例子:
1. 我们创建一个myproc.c文件并编译链接成可执行程序,然后对比./myproc执行和执行myproc执行。
我们发现可执行文件myproc加上./就可以进行运行,但是直接运行myproc却会报错。下面我们再来运行一下系统的指令。
2.为什么系统指令如pwd,ls等可以直接执行,不需要带路径,而我们的可执行程序需要带./路径才能执行呢?
其实是因为我们想要执行一个可执行程序,那么我们第一步就必须得找到它在哪里,然后再去执行它。因为系统不知道proc这个文件在哪,加上./是为了帮助系统找到proc这个可执行程序的。
3.那为什么系统指令就不需要带路径呢?
其实系统指令也带了路径了,系统当中Shell会维护一个PATH环境变量,这个环境变量当中带着我们指令的搜索路径。
我们可以看到环境变量PATH中有多条路径,这些路径以冒号作为分隔符隔开,当我们使用pwd或者ls命令的时候,系统就会依次在环境变量PATH的这些路径中进行查找。
我们通过which看到 pwd,cd,ls 都是放在PATH的其中一条路径下面的。
当我们执行的系统命令在这些路径中找到了就会停止查找,然后执行指令。
4. 有没有什么方法让我们的可执行程序可以不用带路径,直接就可以运行呢?
有的,将我们的程序所在路径加入环境变量PATH当中。
export PATH=$PATH:myproc程序所在路径。
对比测试
从以上运行程序我们可以发现,我们将路径添加到PATH之后就可以运行了。
注意:
修改时这里的指令PATH=$PATH:/....
不能直接使用PATH=/....,这是将path只改成一个路径,发现系统的指令跑不了了。但是这种情况只需要重新登陆即可恢复。
5. 还有什么方法可以不用带路径,直接就可以运行呢?
将你自己生成的可执行程序拷贝到环境变量PATH的某一路径下。
[root@hecs-202562 lesson13]# cp myproc /usr/bin
小结:
1.为什么我们执行指令时不用带路径?shell如何知道我们要执行的指令在哪里呢?
我们新建的可执行程序要运行时往往需要加上./,但系统默认的指令是不需要的如ls,pwd等。因为我们用户登陆时默认就会生成与一个PATH,当我们输入默认的系统指令,会默认到path包含的路径里面找,输入echo $PATH可以打印出其包含的路径,主要每条路径是用:连接的,因此,如果我们想要不输入./就能执行我们新创建的可执行程序,只需要将可执行程序的路径包含在PATH下就可以了,用PATH=$PATH:接新建可执行程序的路径即可。
2.下面我们再来用which看一下我们创建的可执行程序myproc添加到PATH环境变量后能否找到。
找到了,所以我们更加笃定了Which指令就是根据path环境变量来搜索指令的
PATH=$PATH:/home/GTY/lesson13
测试HOME
我们知道cd~命令可以进入到当前用户的家目录,并且每个用户的家目录是不一样的。
那么操作系统它是怎么知道每个用户的家目录是在哪的呢?
因为每个用户的环境变量HOME是不同的,操作系统通过环境变量HOME来保存该用户的家目录
下面我们分别用root和普通用户,分别执行 echo $HOME ,对比差异. 执行 cd ~; pwd ,对应 ~ 和 HOME 的关系
1.root用户执行cd ~; pwd
:
2.普通用户执行cd ~; pwd:
可以看到,root用户的家目录是/root
,而普通用户的家目录是/home/普通用户名
。
这里,~
符号代表当前用户的家目录。因此,在root用户和普通用户下,~
和$HOME
是相同的。
和环境变量相关的命令
1. echo: 显示某个环境变量值
2. set: 显示本地定义的shell变量和环境变量
3. env: 显示所有环境变量
4. export: 设置一个新的环境变量
5. unset: 清除环境变量
环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。
通过代码如何获取环境变量
命令行参数
main函数可以带参数吗?
其实我们的main函数是可以带参数,并且它是有三个参数的,因为我们平时基本上都不怎么用他们,所以我们并没有将这三个参数给写出来。
main函数是有这三个参数的:
int main(int argc,char *argv[],char *env[]);
参数说明:
argc:限定命令行字符串个数, 限定只能传多少个参数
argv : 指向一个个的命令行参数
env: 指向一个个环境变量
下面我们先来看一下前俩个参数:
运行结果:
默认情况下,命令行参数只有一个,就是我们输入的执行程序命令./myproc
下面我们在命令行多输入几个参数,并用空格隔开。
main函数的第二个参数argv是一个字符指针数组,我们将可执行程序以及它后面的选项都看作是字符串,argv的第一个字符指针存放的是可执行程序,后面几个字符指针存放的是可执行程序后面的选项,最后一个字符指针存放的是NULL。
argv指针数组存放了argc个指针,当我们输入命令时,系统将我们的命令按空格分割出来,得到argc个字符串,然后把字符串的地址依次放进到argv数组当中。
我们知道我们可以通过调用系统指令+不同的选项实现不同的子功能,那么这里我们同样可以通过main函数的几个参数来根据你所给的选项不同,从而打印不同的结果或者实现不同的功能。
下面我们来看一段代码:
运行结果:
从上面例子可以理解到,为什么我们的系统命令可以带不同的选项。我们调用的是同一个命令,只是调用不同的选项,查看了不同的内容。
为什么要这么干呢?因为要为指令,工具,软件提供命令行选项的支持!!
命令行第三个参数
运行结果:
我们发现运行结果其实就是输入env指令打印出来的各个环境变量的值。
通过第三方变量environ获取
运行结果:
注意:libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。
通过系统调用获取或设置环境变量
我们还可以通过调用getenv函数来获取环境变量,这也是我们最常用的一种方式。
getenv函数可以根据所给的环境变量名,在环境变量表中进行搜索,从而找到对应的环境变量拿出后面的内容。
下面我们来看一段代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
环境变量通常是具有全局属性的
俩张核心向量表!
1.命令行向量表 2.环境变量表
我们一个进程在运行时,不要简单认为我的进程启动就是把程序加载到内存,而是当我们的程序变成进程在启动时,我们一定要有人调main函数,给main函数把这俩张表传进来,一张是命令行参数表,另一张是环境变量表。
上面程序打出来的环境变量和我们的shell打印出来的环境变量是一样的。因为我们自己的进程本身是没有环境变量,但当他启动起来,变成进程之后就具有环境变量,因为./运行我们的myproc之后,它会变成进程,而./myproc又是我们的bash的一个子进程。
结论:我们所运行的进程,都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我的环境变量!
环境变量是系统提供的一组name=value形式的变量,不同的环境变量有不同的用户,通常具有全局属性。
这就是我们上面所说的环境变量具有全局属性,可以让我们的子进程继承下去。
那么如何验证这件事情呢?
首先定义一个本地变量,然后将它export进去( 命令行直接定义的是本地变量,要变成环境变量要将它export一下)
此时我们的系统中的环境变量就新增了MYVALUE这个环境变量
运行结果:
我们的MYVALUE还只是一个本地变量,并不是一个环境变量,它只能够父进程自己去用,所以什么都没有打印。
下面我们让父进程bash通过export指令,将MYVALUE变成环境变量再来看一下吧
可以看到子进程环境变量也新增了,说明子进程继承了父进程的环境变量。
总结:
- 本地变量, 本地变量指的是我们可以在命令行当中直接定义,但不是定义在环境变量,只会在本BASH内部有效,不会被继承,将本地变量导入环境变量:用export。
- 环境变量具有全局属性,本质是环境变量可以被子进程继承下去。
- 环境变量会影响整个"用户系统",影响bash的子进程,逐层往下影响。