文章目录
- 环境变量
- 基本概念
- 常见环境变量
- 和环境变量相关的命令
- 为什么带./运行我们的可执行程序
- 本地变量
- 环境变量的组织方式
- 环境变量具有全局属性
环境变量
基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找.
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
常见环境变量
前面我们也提过:如何查看环境变量:echo &PATH
其中NAME是环境变量的名称
- PATH : 指定命令的搜索路径
- HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的家目录)
- SHELL : 当前Shell,它的值通常是/bin/bash
- 以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类
和环境变量相关的命令
export: 设置一个新的环境变量 echo: 显示某个环境变量值(环境变量和本地变量的值都可以显示) echo $环境变量名
env: 显示所有环境变量
unset: 清除本地变量 || 环境变量
部分环境变量说明:
环境变量名称 | 表示内容 |
---|---|
PATH | 命令的搜索路径 |
HOME | 用户的主工作目录 |
SHELL | 当前Shell |
HOSTNAME | 主机名 |
TERM | 终端类型 |
HISTSIZE | 记录历史命令的条数 |
SSH_TTY | 当前终端文件 |
USER | 当前用户 |
邮箱 | |
PWD | 当前所处路径 |
LANG | 编码格式 |
LOGNAME | 登录用户名 |
为什么带./运行我们的可执行程序
Linux下一切东西皆是文件,我们执行自己的可执行程序,为什么要带./
来运行呢? (本质是运行当前目录(.)下的可执行程序)
要执行一个可执行程序必须要先找到它在哪里,既然不带./就可以执行系统命令,说明系统能够通过命令的名称找到指令的位置,而系统是无法找到我们自己的可执行程序的, 带./
是为了找到对应的程序,告诉系统该可执行程序位于当前目录下,当然我们也可也使用绝对路径和其它相对路径来运行程序
系统的命令也是文件,为什么可以直接执行,而不用带路径呢?
这是因为环境变量PATH的原因 ,PATH:指定命令的搜索路径
例子:如何查看环境变量:echo &PATH
其中NAME是环境变量的名称
以:
作为分隔符,分隔出多条路径,当执行系统命令的时候,会从左到右依次逐级查找
同样我们可以使用which
指令查看指令的保存路径:可以发现这个路径就在PATH里面
当然我们也可也把我们的可执行程序加到PATH路径里面,那么我们执行可执行程序,就可以直接使用可执行程序的文件名字来直接运行
错误方法:exprot PATH=可执行文件的路径
-> 这种做法相当于是直接把环境变量覆盖了!
如何撤销?重新启动xshell
正解: 方法1:把命令(我们自己写的可执行程序也可以看做是某种命令) 拷贝到环境变量PATH的某一路径下
sudo cp 可执行程序 /usr/bin
但是不推荐这种方法,因为会污染命令池
现在我们知道,所谓的安装软件,就是把软件拷贝到系统环境的某一特定路径下
方法2:将我们的当前可执行文件的路径添加到环境变量PATH中 (这种方法只在当前登陆有效)
导入环境变量:export PATH=$PATH:可执行文件的路径
这里设置的是内存级的环境变量,并没有写入到系统文件中,只在当前登陆有效
本地变量
本地变量只在本次登陆有效
**set:**显示本地定义的shell变量和环境变量
- 注意:直接使用set会显示所有的内容, 我们一般搭配行过滤工具
grep
使用
unset: 清除本地变量 || 环境变量
环境变量的组织方式
main函数实际是可以带三个参数的,
int main(int argc,char* argv[],char* env[])
参数说明:
- argc:限定命令行字符串个数, 限定只能传多少个参数
- argv : 指向一个个的命令行参数
- env: 指向一个个环境变量
int main(int argc,char* argv[],char* env[])
{
if(argc!=5) //限制只能传5个参数
{
return 1;
}
//....
}
例子:
#include<stdio.h>
int main(int argc,char* argv[])
{
for(int i = 0;i<argc;i++)
{
printf("argv[%d]->%s\n",i,argv[i]);
}
return 0;
}
- argv:指针数组
- **env:**指针数组,是一个环境表
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
上述的argc和argv是命令行参数, env环境变量
命令行参数存在的价值:
指令有很多选项,用来完成同一个命令的不同子功能.选项底层就是通过命令行参数实现的
我们可以通过给同一个函数带入不同参数的方式,执行不同的逻辑.
例子:
#include<stdio.h>
#include<string>
int main(int argc,char* argv[])
{
//限定只能传两个命令行参数
if(argc!=2)
{
printf("Usage:%s-[a|b]\n",argv[0]);
return 0;
}
if(strcmp(argv[1],"-a"))
{
printf("hello -a\n");
}
else if(strcmp(argv[1],"-b"))
{
printf("hello -b\n");
}
else //带其它参数
{
printf("hello\n");
}
}
执行效果:
指令有很多选项,用来完成同一个命令的不同子功能,选项底层使用的就是我们的命令行参数,这也是命令行参数的意义
通过程序获取环境变量:
方法1:通过env指针数组
因为env指针数组的最后一个元素是NULL,所以我们可以直接使用env[i]作为结束判断
env的参数个数不需要判断,是系统提供的,只需要使用即可
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
for(i=0; env[i]; i++)
{
printf("%d->%s\n",i,env[i]);
}
return 0;
}
方法2:通过第三方变量environ获取
environ是系统提供的第三方变量,类型为char**,指向环境表的起始地址
environ+i:第i个环境变量的地址 environ[i] = *(environ+i):第i个环境变量的内容
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明
#include <stdio.h>
int main(int argc, char* argv[])
{
extern char **environ;//先声明外部变量
int i = 0;
for(i = 0; environ[i]; i++)
{
printf("%s\n", environ[i]);
}
return 0;
}
方法3:可以通过环境变量名,获取环境变量的内容 getenv函数可以获取环境变量的内容
例子:
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("%s\n",getenv("PATH"));
printf("%s\n",getenv("HOME"));
printf("%s\n",getenv("SHELL"));
return 0;
}
本质是:拿着变量名 ->找到环境变量 -> 再拿到变量中的内容
如果让我们自己设计一个getenv
:
例如:getenv("PATH")
方法:遍历所有的环境变量查找, 例如:strstr(target,"PATH=")
target代表的是当前遍历到的环境变量,找到之后, 从target起始位置+PATH=
的字符串长度,跳过前面的内容, 来到/位置,然后要的是/后面的内容
例如:PATH=/isr/sbin:/usr/bin:/sbin:/bin\0
此时我们要的是:/isr/sbin:/usr/bin:/sbin:/bin
环境变量具有全局属性
环境变量具有全局属性,本质是因为环境变量可以被子进程继承的
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("I am a process PID:%d PPID:%d\n",getpid(),getppid());
return 0;
}
如果我们多执行几次,可以发现:该进程的PID一直在改变,PPID始终保存不变,这是为什么呢?
进程在不断新建,但PID会改变,.命令行上启动的进程,父进程都是bash
,即命令行解释器
如何证明环境变量具有全局属性?
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("My_envVal:%s\n",getenv("My_envVal"));//通过getenv函数获取My_envVal环境变量的内容
return 0;
}
环境变量会影响整个"用户系统"