环境变量!
环境变量
我们是否可以认为我们平时写的程序是一个指令呢?可以的!
其实我们平时写的程序和我们在linux下执行的指令是同一个东西!
都是可执行程序!
那为什么我们执行的时候,需要用到./xxx这样来执行我们的程序,但是使用系统里面的指令就只要输入就可以呢?
我们从报错我们就可以看出要执行一个程序,就要先找到这个指令!
而 ./ 就是当前路径!通过这个系统找到我们程序的!
==所以有两种方法来使我们的程序变的像指令一样使用==
- 将我们的程序拷贝在==/usr/bin/==这个路径下!——但是不建议因为我们的程序没有经过测试,没有经过测试的程序最好不要安装在系统里面!会污染指令池==拷贝就是linux的安装!==
- ==修改环境变量==——PATH
PATH
==PATH是系统中的一个环境变量!操作系统在启动的时候会在shell的上下文之中给我们定义的一个环境变量!是全局有效!==
echo PATH//这样查看是不行的!
echo $PATH//这样才能正确查看!
我们可以看到里面有很多的路径!每个路径都按照 : 来分隔开来!
==而操作系统在执行指令的时候就是在这些路径下面!来一个个的检索对应的指令!如果指令存在运行!如果不存在就报错!==
==所以我们只要让我们的路径添加到PATH里面就可以像系统指令一样的去使用了!而且还不会影响指令池!==
export
export就是一个用来专门修改环境变量的指令!
export的错误用法
export PATH=xxxxx//指某个路径
这样写会发生什么事情?
==会导致这个环境变量下面的所有路径被这个路径给覆盖了!==
所以绝不可以怎么写,这样还会导致所有的指令都失效了!
==不过解决的方法也很简单重启一下就好了,因为这只是一个内存级的环境变量==
定义命令行变量
linux的命令行解释器是可以定义命令行式的变量,环境变量也是属于这的一种!
环境变量其实很好理解
==我们要明白shell本质也是一个进程!==
我们以前在写c/c++程序的时候!我们会去使用new/malloc来申请空间!
new/malloc就是在进程运行的时候申请空间的!
也就是说进程在运行期间是可以对它的空间进行动态的调整的!
有了空间就可以存储数据!环境变量本质也是一个数据!就是一个字符串!
所以在命令行上面定义环境变量其实也是差不多的效果!就是申请空间将数据保存起来!
环境变量哪里来的
上面我们说到PATH这个环境变量重启之后就可以恢复!但是是根据什么来恢复的?
答案是在用户的工作目录下面的两个文件!
我们进入.bash_profile里面看
里面开始就是一个shell脚本 —— 当前工作路径下.bashrc如果存在就执行它
然后里面也定义了一个环境变量 然后导环境变量!
.bashrc里面的内容也是相似的!会先去检查系统/etc路径里面的bashrc会不会存在存在会去执行它!
而这个系统bashrc里面会会存在很多的动作用来构建环境变量!
vim /etc/bashrc //用vim进行查看!
==而系统每次启动就会把当前工作路径下的bash_profile执行一次,将环境变量导入当前的shell中!==
==所以内存中就会存在一个PATH,即使我们将它覆盖了下一次系统启动后也会重新根据这个生成出来!==
==这种具有全局属性和特殊功能的变量我们称为环境变量!==——也可以怎么说环境变量就是操作系统为了满足不同的应用场景而预先在系统内设置的一堆全局变量!
==就是有各种各样的环境变量!操作系统才能完成各种各样的功能!所以才需要开始就预先设置好!==
其他各种环境变量
HOME
这个环境变量就是当前用户的工作目录!
所以我们使用 **~**的时候本质就是进入$HOME所对应的路径下!
cd ~ cd $HOME//这个和上面的结果是一样的!都是切换到当前的工作目录!
HOSTNAME
这个环境变量对应的是主机名
LOGNAME
这个是对应的这个系统的用户名!
HISTSIZE
当我们在命令行按上下的时候,就会显示出以前的历史的指令!
这个就是就是可以记录的历史命令的数量!
PWD
这个环境变量记录着我们的当前路径!
当我们的路径改变的时候!bash也会跟着修改PWD的这个环境变量的值!
我们调用ls指令 我们查看当前路径下的时候都是直接后面跟文件名的!
ls test.c
例如上面这样!==而其实ls是通过调用PWD这个环境变量用来知道我们所处的路径的!==
环境变量相关指令
echo
显示环境变量的值!
echo $xxx// xx就是环境变量的名称!
env
用看查看所有的环境变量!
这些都是系统里面的环境变量!
getenv——相关函数!
这是一个函数专门用来获取环境变量的!
这是一个用来专门==获取环境变量的C语言函数接口!==
返回值是个该变量的指针!如果找不到就返回一个null
使用
#include <stdio.h> #include <stdlib.h> #include <string.h> #define USER "USER" int main() { char* who = getenv(USER); if(strcmp(who,"root")== 0) { printf("user:%s\n",who); printf("user:%s\n",who); printf("user:%s\n",who); printf("user:%s\n",who); printf("user:%s\n",who); } else{ printf("权限不足!\n"); } return 0; }
USER的环境变量的最大意义就在于可以识别当前linux用户!
==linux的很多指令都是通过USER来识别的!==
export
用来修改环境变量!
==也可将命令行的上定义的本地变量变成环境变量!==
我们可以用以下代码来验证
#include <stdio.h> #include <stdlib.h> #include <string.h> #define USER "USER" #define MY_ENV "myval" int main() { char *myenv = getenv(MY_ENV); if(myenv == NULL) { printf("%s,not found\n", MY_ENV); return 1; } printf("%s = %s\n",MY_ENV,myenv); }
我们可以发现是找不到!
但是如果我们使用
export myval export myval=1000//也可以这样定义的时候导
我们上面说过!bash本质是一个进程!而mycmd本质也是一个进程!是bash的子进程!
通过的是fork函数来实现的!
==而我们的环境变量是定义在bash这个进程上的!==
==但是我们的子进程也可以识别到这个环境变量!==——这个说明全局变量,==具有全局属性的根本就是环境变量会被子进程给继承下去的!==
为什么要继承下去?
为了适应不用的应用场景!
==像是我们使用cd这个切换指令!当我们不是root用户的时候想要切换到home目录下的其他用户的路径的时候!我们就会被告知权限不足!cd指令本质也是一个子进程!就是通过继承读取USER这个环境变量来做身份认证的!==
==而区别的本地变量!(还没有用exprot导入的)就只在当前的进程(bash)下面有效!==
set
即显示本地变量!又显示环境变量!将所有的变量显示出来!
unset
==取消环境变量!==
这样环境变量就被我们取消了
==取消本地变量!==
命令行参数
我们使用的main()函数虽然我们一般都是这样使用的!
但是main函数本质也是有参数的!一共有三个
int main(int argc ,char* argv,char* envp[]);
那么这三个参数分别有什么用吗?
argc
argc相当于是第二个数组的大小!
argv
而且我们都知道main函数是一个主函数!那么是谁调用了main函数? ——是操作系统!
==argv是一个指针数组!==那么重点来了?那它的值是谁传的?——就是操作系统/父进程
那传的是什么呢?
我们可以测试一下!
#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数组的内容其实就是命令行上的内容!==——命令行上的内容都是要传给argv的!
==第一个就是程序名!剩下的都是选项!==
==同理我们使用的一些指令!例如 ls都是一样的!ls -a -l 这个会被传入到ls这个程序里面的argv数组!==
==这个工作是由shell和操作系统一起完成实现的!==
那么这个参数的最大的意义是什么呢?
==假如我们以后写一个程序 想要让这个程序根据不同点选项执行程序内不同的功能的时候!那么这个参数就会发挥用处了!==(例如ls 我们可以在后面跟上 -a,-l之类的选择让它执行不同的功能!)
举个例子
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc,char* argv[]) { if(argc != 2) { printf("Usage: \n\t%s [-a/-b/-ab/-ac/-bc/abc]\n",argv[0]); return 1; } if(strcmp("-a",argv[1])== 0) { printf("功能a\n"); } if(strcmp("-b",argv[1])== 0) { printf("功能b\n"); } if(strcmp("-c",argv[1])== 0) { printf("功能c\n"); } if(strcmp("-ab",argv[1])== 0) { printf("功能ab\n"); } if(strcmp("-bc",argv[1])== 0) { printf("功能bc\n"); } return 0; }
==例如在ls下面执行不同的打印就是通过命名行参数!来读取继承获得的!==
envp
也是一个指针数组!
只不过它指向的是一个个的环境变量!结尾也是NULL
==环境变量的就是一行行的字符串!==
所以其实当main函数被调用的时候!如何带有这些参数!
==那么系统就会自动的生成两张表!一个是命令行参数表!一个是环境变量表!==
每个进程都会生成!
==这就是为什么进程可以拿到环境变量的原因!==
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc,char* argv[],char* envp[]) { for(int i = 0 ;envp[i];i++) { printf("envp[%d] = %s\n",i,envp[i]); } return 0; }
我们发现所有的环境变量全都都导入到了这个进程里面!
==我们发现我们导入的环境变量也可以被传进入!==
environ
==如果我们既不想用环境变量参数envp也不想使用getenv话C语言还为我们提供了一个参数让我们来使用!==
这是一个==全局变量的二级指针!这个指针本质其实就是指向envp这张表上==使用这个参数前面要加上extren
我们可以通过这来访问环境变量!
==因为数组传参的时候会发生降维,会降维成只想内部元素类型的指针!==
所以envp发生降维就是内部元素是char*型,那么降维就是char**
#include <stdio.h>
#include <unistd.h>
//int main(int argc,char* argv[],char* envp[])
int main()
{
extern char** environ;
for(int i = 0 ;environ[i];i++)
{
printf("environ[%d]=%s\n",i,environ[i]);
}
return 0;
}
这样我们就有在我们进程的上下文中获取环境变量的三种方式!
- getenv——函数!
- envp参数!
- environ——二级指针!
不过我们一般都是使用getenv更多!
putenv
putenv是改变或者添加一个环境变量!