Linux环境变量

在这里插入图片描述

汇总

本文涉及到关于环境变量的指令和函数:
echo $XXX - 显示当前环境的环境变量XXX
export - 导出环境变量(为当前环境设置一个新的环境变量)
env - 显示当前进程的所有环境变量,一般为bash
unset - 删除当前进程的环境变量
set - 显示当前进程的本地变量和环境变量
getenv() - 获取环境变量X=Y,getenv(X) return Y;
environ - 第三方变量,不通过env[]命令行参数的方式,打印所有的环境变量

windows下环境变量

在[此电脑]处右键,[属性],[系统信息]中[高级系统设置]下有一个[环境变量]
在这里插入图片描述
打开就能看到用户的环境变量,左边是环境变量的变量,右边是值,是操作系统帮我们维护的一组kv(key value)值
在这里插入图片描述

初识环境变量

我们先来看一看一些常用的环境变量

环境变量一

我们在Linux中指令就是C、CPP、汇编写的程序,为什么我们自己写的程序,运行时,需要**./mycode.exe**,而像ls pwd这些指令,就可以直接运行,不需要 ./ 呢?
我们which ls或者which cd,寻找到的路径是/usr/bin/XXX,这个/usr/bin就是系统的默认指令的路径之一
这里就有一个环境变量 —— PATH是在我们登陆了xshell后就长期存在于内存中了,我们可以用echo $PATH查看该环境变量的内容
在这里插入图片描述

这里查看到的路径是用冒号作为分隔符,这些路径就是操作系统用于查找指令的路径,也就是说:当我们在运行指令的时候没有加上绝对路径的话,就会在PATH中一个一个路径下依次寻找

比如我这台电脑在执行ls时,操作系统现在/usr/local/bin中寻找ls,发现没有找到,然后去/usr/bin中寻找,找到了ls,所以此时就执行ls
我们不加./去运行我们自己写的程序,只会在PATH路径下寻找指令,发现这些目录下,都没有code.exe文件,所以
就会报出:-bash:code.exe: command not found
在这里插入图片描述
如果我们此时,把code.exe拷贝到PATH路线下,运行code.exe就能够正常运行

但如果,我们不想添加到PATH中,又想直接执行,此时就需要添加环境变量

PATH=[新路径],就能够让PATH路径改为等号后面的路径,这里需要注意的是,PATH=[新路径],是把PATH中的路径替换为新路径,也就是说旧的路径就没有了,所以我们如果只是想另增新路径的话,$PATH可以更便捷的拿到所有旧的路径,然后加一个冒号,然后后面加上想要加的新的路径,如下图
在这里插入图片描述
此时我们再次运行code.exe
在这里插入图片描述
就能够直接运行该指令,此时/home/upset_grass/practice_-linux/Practice2023-9-22这个路径下的所有指令,都能够直接运行,就不需要用相对路径或者绝对路径去寻找该路径下的指令

此时,which指令也能够直接查到code.exe的路径了(which指令只能查找PATH路径的目录下有的指令)
在这里插入图片描述

如果我们把PATH路径不小心直接替换为/home/upset_grass/practice_-linux/Practice2023-9-22,不要其他的路径了
执行各种指令时发现,绝大多数指令都无法直接运行了,还是有极少数的指令能够运行,比如echo、pwd,后面会解释
在这里插入图片描述
这种情况我们有两种解决方式,第一种,我们寻找到之前的所有路径,然后PATH=[XXX]重新设置路径(之前echo $PATH过的话可以用这种方法)
在这里插入图片描述
第二种方法:关掉XShell,再次打开,之前的路径就回来了,因为我们使用PATH=[新路径]的方式是一种内存级别的,也就是我们修改的是内存中的环境变量,当我们关闭XShell,重新登陆XShell,原来的路径都又出现了,也就是说,环境变量是存储在了磁盘上的一些配置文件中的,当我们系统启动时,会从配置文件加载到内存中

环境变量二

为什么我们登陆xshell以后,是在家目录(/root /home/upset_grass),不在根目录或者其他目录下?
在这里插入图片描述
这是因为HOME环境变量的存在
在我们通过XShell登陆用户时,bash命令行读取到该用户登陆,通过该用户的HOME环境变量,类似于cd $HOME这样的操作,把自己放到了家目录下,完成了用户登陆时自动处于家目录下的操作

更多的环境变量

除了像PATH,HOME,还有别的像SHELL,USER,TZ等环境变量
我们可以通过env(environment)命令来查看所有环境变量
在这里插入图片描述
HOSTNAME - 主机名,也就是你这台机子的名称

HISTSIZE - 历史命令存储容量,我们可以通过history命令来查看我们历史上输入过的指令

SSH_TTY - 终端设备,一个终端设备在这里也就是一个会话,我们为什么在echo "hello"时,能够在这个会话中显示hello,依靠的就是SSH_TTY,SSH_TTY存储的是一个字符设备文件,我们通过ls /dev/pts/0可以查看到这个字符设备文件
如果我们现在有一个会话1,会话1的SSH_TTY是/dev/pts/0,我们另开了一个会话2,在在会话2中通过echo “hello” > /dev/pts/0,就能够把hello信息输入到会话1中

LS_COLORS - ls时的配色方案

PWD - 当前所处的路径,PWD会存储当前我们所在的路径
在这里插入图片描述

LOGNAME - 登陆用户

OLDPWD - 上一次所在路径,我们回忆之前cd - 命令,我们能够回到上一次所在的路径,其原因就在这里,环境变量中有一个OLDPWD来记录上一次所在路径,以便于我们能够快速回到上一次所在路径,所以我们的cd - 会被解释为 cd $OLDPWD

这里我们再来测试,环境变量USER和LOGNAME
在这里插入图片描述

我们在whoami的时候显示的是root,当我们在su - 登陆其他用户时,LOGNAME和USER都会变成su - 后的用户
在这里插入图片描述
对于su和su - 的区别就在这里,su是单纯切换用户,但是还是原来用户的环境变量,但是su - 切换用户时,也会切换环境变量

上面是通过指令获取环境变量,下面我们在程序中通过接口获得环境变量

获取环境变量有一个系统接口getenv()
在这里插入图片描述
这个接口的作用就是,通过给环境变量名,然后返回环境变量的内容
在这里插入图片描述

所以我们能够通过这个接口,使得对于不同的用户,执行同一个程序,结果不同
在这里插入图片描述
也就能够支持不同的用户,进行设置不同的执行分支
在这里插入图片描述

也就是程序能够通过getenv获取程序执行者是谁,进而和文件的拥有者、所属组、文件的权限等产生联系,就能够判断该用户是否有读写执行权限

除了getenv获取单个环境变量,还有environ全局变量,获取全部环境变量
在这里插入图片描述
用extern关键字来获取到第三方变量environ,然后environ[i]就能获取到每个环境变量,同理environ在所有环境变量结束后面置空了,结束条件可以直接用environ[i]
在这里插入图片描述

环境变量

环境变量是系统系统的一组name=value形式的变量,不同的环境变量有不同的用途,通常具有全局属性
并且环境变量不是在进程的创建时才会出现的,而是在系统启动,用户登陆时,环境变量就已经生成了

为了理解,环境变量具有全局属性,我们先了解了解命令行参数

命令行参数

main函数能够带参数int main(int argc, char* argv[]){}
这里的argc和argv就是命令行参数,在windows编程中,我们基本不需要使用这两个参数,但是在Linux编程中会经常使用到这两个参数,这两个参数和"选项"有关,argv是指针数组,argv中保存的元素是字符串的地址,argv的v是vector,是一个向量表,也称argv是命令行参数表, argc保存的是argv数组的元素个数,我们可以通过程序来理解理解
在这里插入图片描述
对于这里的循环终止条件,我们还可以改写为for(; argv[i]; i++){}这是因为在argv[]指针数组的结尾出被置为了NULL
在这里插入图片描述
下图显示了argv指针数组在内存中的存储
在这里插入图片描述

这里我们在运行程序时,后面 带上选项-a -b等选项
在这里插入图片描述
此时发现argv增多了

这是因为,对于用户层面,main函数是第一个被调用的函数,但是实际上在C语言程序被编译好后,第一个调用的函数是Startup(),在Startup中调用了main函数,给main函数传递了两个参数argc和argv,这两个参数是通过bash翻译我们的命令./code.exe -a -b -c而来的,具体则是:bash命令行读取./code.exe -a -b -c这个命令,实际读取到的是"./code.exe -a -b -c"这个字符串,然后以空格为分隔符,把这个字符串打散成"./code.exe"、“-a”、“-b”、“-c”,(这里的打散工作是由bash做的,称为命令的解析操作)一共打散成了多少个字符串,就初始化argc为多少,并把每一个字符串的起始地址给到一个指针数组,然后传给main

也就是说我们此时可以通过指令的不同选项,给argv指针数组传递不同的内容,依次在程序中进入不同的执行分支,我们简单的写一个程序
在这里插入图片描述
此时我们带上不同的选项,就能执行不同的分支
在这里插入图片描述
命令行参数能够为指令、工具、软件等,提供命令行选项的支持!

这里可能有些同学有疑问,为什么main函数可以带参数,也可以不带参数?
这是因为编译器会检查main函数的参数,就能在编译器生成的Startup函数中选择是否给main函数传参数

环境变量表

main函数的参数只有argc和argv吗?命令行参数和环境变量有什么关系?
还有别的参数,int main(int argc, char* argv[], char* env[])
这第三个参数env和argv的结构一模一样的,都是指针数组,结尾出都用NULL置空了,称为环境变量表
我们同样可以用程序打印所有的环境变量
在这里插入图片描述
在这里插入图片描述
并且我们这里发现,env[i]的顺序和我们用env指令打印的环境变量的顺序完全一致,那么我们今后,就可以通过env[]来获取环境变量,想获取哪个获取哪个,而不需要通过getenv()获取具体的那一个环境变量

所以,对于每一个C、C++程序,都有两张核心向量表:1、命令行参数表,2、环境变量表

我们思考,我们在没有执行./mycode.exe时,可以通过指令env来获取环境变量,这是bash做的,其原因在于bash本身在启动时,会从操作系统的配置文件中读取环境变量信息,存储到一张环境变量表中(指针数组中),因此可以通过bash自己的函数(env)去获取环境变量
对于我们自己写的mycode.c程序,可以通过main的命令行参数char* env[]的方式,去继承父进程bash的环境变量,而我们自己写的mycode.c其子进程,也可以通过相同的方式,继承环境变量,所以我们说环境变量具有全局属性

环境变量的新增

我们可以增加新的环境变量
在这里插入图片描述
这里我们添加了一个MY_ENV变量,给MY_ENV赋值为hello,我们可以echo打印这个变量,但是这个变量目前在env中还不存在,我们称这个MY_ENV变量为本地变量。只有当我们在定义MY_ENV变量时,加上export(导出)才能让MY_ENV变量变成环境变量
在这里插入图片描述
这个我们自己定义的环境变量也能够继承给子进程
在这里插入图片描述
我们可以用unset把自己创建的环境变量删除掉在这里插入图片描述

本地变量和内建命令

本地变量

本地变量 —— 可以直接在命令行中定义,可以通过[$本地变量]的方式打印本地变量存储的值,我们的env可以查看到环境变量,那么我们还可以通过set命令,查看到系统的本地变量和环境变量,并且本地变量是不会被子进程继承的,只会在bash内部有效
在这里插入图片描述
本地变量有什么用?
简单观察两个本地变量
在这里插入图片描述

这里的PS1表示的就是命令行的打印形式,[\u@\h \W]\$其中\u就是用户名\h就是机器名\W就是当前目录位置,$就是命令提示符,对于PS2,当我们在输入命令后面加上一个 \ ,之后会出现 > ,这个 > 就是PS2来的,\ 的作用类似于命令延续在这里插入图片描述
对于所有本地变量,都可以通过export(导出)的方式变成环境变量
在这里插入图片描述
并且这里本地变量通过export变成了环境变量之后,是能够被子进程继承的
在这里插入图片描述
在这里插入图片描述

但是这里有一个疑问,本地变量是不能继承的,为什么echo指令能够打印本地变量呢,echo不会创建一个子进程吗?

内建命令

命令行上的指令并不是所有都需要创建子进程
这里我们讲命令分为两种:常规命令、内建命令
1、常规命令:通过创建子进程完成命令
2、内建命令:bash不创建子进程,而是由bash自己执行,可以初步理解为bash调用了自己写的、或者系统提供的函数,也就是没有通过fork来创建子进程执行命令,而是自己来做,所以上面所说的疑问echo能够打印本地变量就不奇怪了,因为就是bash自己内部的函数,就是在当前进程中的,直接获取到打印即可

类似的cd命令,对于每个进程都有自己当前的工作目录,cd命令改变的是当前进程的目录位置,所以如果创建了子进程,并不能影响到父进程bash的工作目录,所以cd命令也实现成了内建命令

cd命令是如何实现的——系统调用接口chdir
在这里插入图片描述
参数const char* path就是目标路径,也就是让当前进程的工作目录跳转到path路径

我们这里写一个测试代码
在这里插入图片描述

在第一个sleep(10)等待的这10秒钟之内,我们执行ps ajx | head -1 ; ps ajx | grep mycode.exe指令,查看到该进程的[PID],然后 ll /proc/[PID] ,就能够看到cwd文件,这个文件反应的就是当前进程的工作目录,此时工作目录就是当前目录,然后第一个sleep执行结束,调用了chdir(argv[1])之后,再查看ll /proc/[PID],此时进程的工作路径就变成了./mycode.c [新的工作路径]
在这里插入图片描述
当然子进程无法影响父进程,所以这里的变化并不能影响bash的工作目录,所以,也可以理解为什么cd指令是内建命令,并且上面我的代码逻辑,就是类似于bash中对于cd命令的处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失去梦想的小草

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值