文章目录
问题引入
在linux系统下,为什么我们编译好的文件要
./+文件名
才能运行,而指令,如ls,pwd...
却可以直接运行?
想要解决这个问题,我们就需要学习一下环境变量。
一,执行路径
我们知道,在linux系统下,一切皆文件,无论是系统指令还是我们自己写的文件,本质上都是由程序编写成的文件。他们有的可以执行,有的不可以执行,而我们上面提到的系统指令和文件,都是可执行文件,在linux系统下,执行文件直接输入路径名即可,例如:系统指令的调用,执行可执行文件
如图,为什么上述文件的执行方式有些不同呢?
其实,对于文件的执行,我们是有绝对路径和相对路径来执行的。
1. 相对执行路径
分析上图,执行process文件时,使用的是相对执行路径,.
表示当前目录,/process
表示文件名。这也验证了执行文件用路径名即可。
相对执行路径:不完整的写完路径名,常用形式:
./文件名
2. 绝对执行路径
讲完相对执行路径,我们来看看绝对执行路径。
如图,我们可以使用which
指令来找寻ls
指令的文件路径,然后输入完整的路径名。同样可以得到相同的结果。
绝对执行路径:完整的文件路径名。
二,环境变量——PATH
1. PATH
通过上述的例子,想必我们对文件的执行有一个进一步的了解,此时让我们回到开头的问题。为什么系统指令既没有输入绝对路径,又没有输入相对路径,但他仍然能够执行能?
这是因为linux系统中环境变量PATH的存在。
让我们来看看环境变量PATH是什么。
输入echo $PATH
,查看PATH的内容。
可以看到,有很多个路径名,每个路径以:
来区分。
/usr/local/bin:
/usr/bin:
/usr/local/sbin:
/usr/sbin:
/home/wk/.local/bin:
/home/wk/bin
原理:
这是系统针对每个用户提前准备好系统指令的完整路径名。我们在使用指令的时候,系统中的shell会自动对这个环境变量PATH的路径内容进行遍历,寻找正确且相符的系统指令的完整路径名,然后自动执行。
通过上述对原理的理解,现在算是知道为什么,我们编译好的可执行文件需要加上./
才能执行,而系统指令却不用吧。说到底就是系统指令有环境变量PATH的支撑,可以找到路径来执行,而我们的可执行文件如果不加./
就会找不到路径从而无法执行。
那如果我们也想像系统指令那样直接输入文件名就可以执行,是不是在PATH中配好正确路径就好了呢?答案是肯定的。
2.自定义配置PATH
我们利用下面这条指令export PATH=$PATH:文件路径
将文件路径添加到PATH中
然后查看echo $PATH
环境变量,发现多了一个路径
这样我们就可以像系统指令一样,直接通过文件名执行文件。
除此之外,我们还有另一种方式一样可以达到相同效果。那就是把文件拷贝到PATH中存在的任一路径,这也就是linux下软件的安装大致实现原理。
三,环境变量相关指令
ehco 显示某个环境变量的值
export 设置某个环境变量(本质是将本地变量添加到环境变量表里)
env 显示所以环境变量
set 显示本地定义的shell变量和环境变量
unset 清除环境变量
这里前两个都介绍过了,我们来看看第三个env
上面列出了我们所有的环境变量,我圈了几个常见的,大家可以重点认识一下。
四,用代码获取环境变量
1. main函数的形参
这里先提一个问题,我们所知的main函数能带参数吗?如果能带参数,那么有多少个呢?
main()函数能带参数,且最多能有三个
void main(int argc, char* argv[], char* envp[])
这里解释一下argc,argv,envp三个形参代表的意思
argc 表示 传入参数的个数
argv[] 表示 把传入参数的值存放在argv[]里
envp[] 表示 接受系统中环境变量表,无需传参,系统自己会传入
我们通过下面代码来实现一下,这几个形参的用法:
int main(int argc, char* argv[], char* envp[])
{
int i = 0;
printf("argc = %d\n",argc);
for(i = 0; i < argc; ++i)
{
printf("%s\n",argv[i]);
}
return 0;
}
可以看到,argc表示形参个数,argv[]表示存储的形参值。
我们继续学习,修改一下代码
int main(int argc, char* argv[], char* envp[])
{
int i = 0;
for(i = 0; envp[i]; ++i)
{
printf("%s\n",envp[i]);
}
return 0;
}
看看这回打印出来的是什么
很好,和上面用echo $PATH
出来的环境变量一模一样,充分说明envp[]就是接收到了系统传递过来的所有环境变量。
2. 利用environ获取
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
下面我们使用另一种方式来获取到环境变量
int main(int argc, char* argv[], char* envp[])
{
int i = 0;
extern char** environ;
for(i = 0; environ[i]; ++i)
{
printf("environ[%d] -> %s\n", i, environ[i]);
}
return 0;
}
3. 利用函数获取
利用函数获取环境变量,我们要先认识一下需要使用到的函数。
函数getenv("环境变量名");
在#include<stdlib.h>
里面,当我们想要得到某个环境变量的值时,可以使用这个函数,输入环境变量的关键字,这样就可以取得了。下面是代码实例:
int main(int argc, char* argv[], char* envp[])
{
char *str = getenv("PATH");
printf("getenv = %s\n",str);
return 0;
}
实用案例
a. 写一个自己的pwd
指令
- 编写代码
int main(int argc, char* argv[], char* envp[])
{
char *mypwd = getenv("PWD");
printf("%s\n",mypwd);
return 0;
}
- 配置PATH
- 运行结果
b. 限定用户使用
int main(int argc, char* argv[], char* envp[])
{
char* user = getenv("USER");
if(strcmp(user, "wk") == 0)
printf("用户所有者\n");
else
printf("%s非法用户,无法访问...\n",user);
return 0;
}
五,环境变量的本质
- 环境变量本质就是一张内存级的表,这张表由用户在登录系统的时候,给特定用户形成属于自己的环境变量表。
- 每个环境变量都有自己的用途,有的是进行路径查找,有的进行身份认证,有的进行动态库查找,有的是来确认当前路径…
- 那么环境变量对应的数据是从哪里来的呢,从系统的相关配置文件(.bash_profile,.bashrc) 而来
六,环境变量的继承性
环境变量具有继承性
如:父进程的环境变量可以被子进程访问。
代码证明
- 先引入一个环境变量
export username="wk"
- 然后执行代码程序
int main(int argc, char* argv[], char* envp[])
{
char *myenv = getenv("username");
printf("%s\n",myenv);
return 0;
}
- 分析:process程序是bash程序的子程序。他里面能够获得在bash上面定义的环境变量,所以环境变量是有继承性的,具有全局属性。
提升问题
如图,var
是bash里面的本地变量,不具有全局性,echo
是指令,既然是指令,那就是文件,执行指令就是运行文件,需要开辟进程来运行,即echo
也是bash
的一个子进程,我们说环境变量才有全局性,而var
不是环境变量却能被子进程echo
读取到值呢?
预知原理如何,大家先自行百度(关键词:内建命令)