1.环境变量
功能:给OS提供连接共能或进行某种操作的而媒介。
(1)命令行参数
main函数其实是有参数的:
//还有,但目前先介绍这两个
int argc ,char* argv[]
argv是一个变长数组,用途是存以指令行的空格为间隔的每个字符串,放完后的结尾是NULL:
//这里就是五个字符串
./proc a b c d
argc就是用与记录字符串个数的。
使用场景:
ls -l
ls是一个c语言程序,而-l是ls的一些子功能,也就是后面这些可以视为选项的字符串,可以通过条件语句实现一个程序的一些可选子功能。(因此每种选项的本质就是一个个的字符串罢了)
例:
#include<stdio.h>
#include<string.h>
int main(int argc,char * argv[])
{
if(argc!=2)printf("输入次数错误\n");
else{
if(strcmp(argv[1],"-a")==0)printf("-a功能\n");
else if(strcmp(argv[1],"-b")==0)printf("-b功能\n");
else printf("不存在这种功能:%s\n",argv[1]);
}
return 0;
}
在进程中的体现就是进程中有一张表,argv表,用于储存所有字符从而实现选项功能。
(2)./和没有./的程序区别的原因
前提:要实现一个程序必须要先找到它,系统中存在一些的环境变量就是来帮助系统找到对应程序的二进制文件。
一个体现就是我们将我们的可执行文件拷贝到/usr/bin/路径时再调用就不需要./来说明路径了。
此时就是用到了一个环境变量,PATH(告诉OS去哪些路径下寻找文件),存储内容如下:
cpp
[fengyouyinli@VM-0-2-centos ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
这些路径就是告诉OS在遇到一个只有文件名的文件时,在这些路径下寻找与该文件名相同的文件并调用其的绝对路径。(也就是这些有的就是OS搜索指令时所采用的默认搜索路径)
env:查看OS中的所有环境变量,形式就是名字=内容.例:
cpp
[fengyouyinli@VM-0-2-centos ~]$ env
XDG_SESSION_ID=38183
HOSTNAME=VM-0-2-centos
SHELL=/bin/bash
TERM=xterm
echo $xxx,可以得到该xxx环境变量名的内容:
cpp
[fengyouyinli@VM-0-2-centos ~]$ echo $SHELL
/bin/bash
PATH的具体介绍:
cpp
[fengyouyinli@VM-0-2-centos ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
以:为间隔的就是不同的路径。
当我们输入一个文件名时,系统就会从前往后一个一个的找与该文件名相同的文件,有就调用它,都没有就报无的error信息。(或理解为将该文件名前加上这些绝对路径然后一个一个的匹配,后序操作同上)
PATH=路径 =>直接就将PATH中的数据覆盖掉了(但这个覆盖是暂时的,重启一下就又初始化了)
PATH = &PATH:路径=>用旧数据加新数据一起覆盖旧数据才是正确做法。
(3)bash的两张表
前提:环境变量首先会在磁盘文件备份一个初始数据。
bash内部中有两个表:命令行参数表与环境变量表。
bash进程出现时,他就会给环境变量表开辟一块空间(说明其的本质就是一个指针数组),每一块空间存一个指针,指向一个字符数组,里面存的是每个环境变量的数据。
原理:当一个指令(bash的子进程)出现时,bash进程先拿到该进程,然后bash先将其作为多个字符串存进命令行参数表,然后再将文件名与环境变量表中的PATH中的路径进行匹配.(严格意义上讲环境变量是存储在所有进程中的,只是bash是最早得到环境变量的进程而已)
总结1:环境变量最早是从配置文件中来的,OS的配置文件包含所有的直接/间接的环境变量内容,因此bash是从这些配置文件中读取的值才创建的环境变量表。
(4).bash_profile和.bashrc文件
每一用户的家目录中都有.bash_profile和.bashrc文件这两个文件:
cpp
[fengyouyinli@VM-0-2-centos ~]$ ls -al ~
total 124
//..
-rw-r--r-- 1 fengyouyinli fengyouyinli 193 Apr 1 2020 .bash_profile
-rw-r--r-- 1 fengyouyinli fengyouyinli 360 Apr 1 14:14 .bashrc
//..
bash进程的环境变量表的初始化:有一个bash进程创建时,首先会先调用用户的.bash_profile文件,.bash_profile在调用.bashrc,然后.bashrc就去调用/etc/bashrc,最后将这三个文件中的数据统筹拷贝给bash进程的环境变量表。
因此我们如果直接修改/etc/bashrc中环境变量的值,之后的bash进程的环境变量表的初始化内容就会被永久性修改。
(5)区分寻找文件的方式
例:
cpp
ls test.c -o test
此处有两个文件名ls和test.c,ls的绝对路径是父进程中的PATH中找到的,而test.c的绝对路径是在子进程中的cwd文件中找到的。
(6)环境变量的统一介绍
SHELL:记录bash的绝对路径
cpp
[root@VM-0-2-centos ~]# echo $SHELL
/bin/bash
USER:当前进程的使用用户是谁(LOGNAME与之几乎一样,(区别之一就在无法查出su - 导致的用户改变))
cpp
[root@VM-0-2-centos ~]# echo $USER
root
此处说明su的本质
(1)su:将权限变成了root,但USER却没有变,,说明su只是让该用户有了root权限。
(2)su -:USER直接变成root,说明su - 直接将用户变成了root管理者。
HISTSIZE:bash记录历史命令的最大次数
cpp
HISTSIZE=3000
HOSTNAME:主机名
cpp
[root@VM-0-2-centos ~]# echo $HOSTNAME
VM-0-2-centos
PWD:当前的工作路径
cpp
[root@VM-0-2-centos ~]# echo $PWD
/root
SSH_TTV:所在终端
cpp
SSH_TTY=/dev/pts/0
OLDPWD:上一次所在的路径
解释了 cd -前往上一次路径的功能,出现-就将其替换为OLDPWD即可。
总结有环境变量就是OS中用于操作系统运行环境时所需的一些参数数据,大部分时候用于给bash用,而用户使用进程时或多或少会使用到bash,因此用户也是会间接使用到环境变量的。
(7)获取环境变量的方式
export :指令,用于创建新的环境变量
unset :指令, 删除某个环境变量
cpp
//创建环境变量
export MY=114514
//删除环境变量
unset MY
1.main函数还有一个参数char*env
env就是该进程的环境变量表。for(int i = 0;env[i];i++)即可遍历,因为最后一位是NULL
main函数是被_start这个函数调用的(linux),用于确保main函数能接受各种参数次数的main函数
cpp
//部分逻辑,代码不一定正确
void _start()
{
int ret = 0,arg_count = 0;
//...
if(arg_count == 0)
ret = main();
else if(arg_count == 2)
ret = main(argc,argv[]);
else
ret = main(argc,argv,env);
}
环境变量可以被子进程继承且环境变量通常具有全局属性,原因:
几乎所有的子进程都可以追述到bash上,因此大部分的进程的环境变量都一样。
2.getnev
getnev:一个函数,以环境变量名字的字符串为参数,返回值为该环境变量的对应内容。
因为知道登录程序用户的进程只有bash,因此提取USER即可区分不同的用户了
cpp
int main()
{
const char*who = getnev("USER");
//return NULL说明返回错误
if(who == NULL)return 1;
return 0;
//xxxx为指定用户名
//条件区分不同用户
if(strcmp(who == "xxxx")==0)//..
else //..
}
3.environ
进程中的一个全局变量,在unistd.h头文件中且要extern char**environ申明后才能使用。
是一个指向进程中的环境变量表的二级指针。
(8)环境变量的特性
(1)有全局特性
(2)指令:
cpp
//指令,生成一个i的本地变量
i=10
bash会定义两种变量(本地和环境)
本地变量不会被子进程继承,只会在bash(父进程)内部中使用。
本地变量是用与写bash脚本的。
(9)expired指令作为一个bash的子进程,如何传给bash环境变量的
expired其实没有创建子进程,其的本质是内建命令由bash进程自身实现(bash自己调用函数,由其的父进程系统调用完成)(此时依旧无法解释PTAH被删了,子父进程中的PTAH都没得情况pwd依旧能调用的原因)
.sh后缀文件,内部能放一堆指令,bash xxx.sh能直接一次性的调用完里面的所有指令。