【Linux初阶】环境变量 | 如何设置、获取环境变量?

 🌟hello,各位读者大大们你们好呀🌟

🍭🍭系列专栏:【Linux初阶】

✒️✒️本篇内容:讨论为什么指令作为一个可执行程序不需要加 ./运行;环境变量为什么会自己恢复;环境变量基本概念;常见环境变量;查看、设置、清除环境变量的方法;环境变量命令汇总;进程中获取环境变量的方法。

🚢🚢作者简介:本科在读,计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-

目录

一、为什么指令作为一个可执行程序不需要加 ./ 运行呢

二、我的环境变量为什么会自己恢复

三、环境变量的基本概念

四.常见环境变量

五.查看环境变量方法

1.查看所有环境变量

2.查看确定名称的环境变量

3.设置/读取本地变量方法

(1)设置本地变量 

(2)读取/打印本地变量

(3)本地变量不可使用环境变量的方法查看

4.设置/读取自定义环境变量方法

(1)定义一个环境变量

(2)查看自定义环境变量

5.清除环境变量方法

 六、环境变量相关的命令汇总

七、环境变量具有全局属性

八、PWD - 记录当前路径的环境变量

九、在进程上下文中,获取环境变量的三种方式

1.getenv获取环境变量

2.char *enc[ ]获取环境变量

3.extern char** environ获取环境变量


一、为什么指令作为一个可执行程序不需要加 ./ 运行呢

通过file我们特定目录下的  ls指令,我们发现 ls指令实际上是一个executable(可执行程序),那么问题来了,为什么它不需要加 ./ 运行呢?

我们结合上面的图解,分析问题,我们大概知道,要想运行一个程序(指令),首先需要找到这个程序。我们自己写的程序要想它运行起来需要加 ./ 的原因就在于,我们需要在当前目录下找到这个运行文件。

要执行一个程序(指令),要先找到这个程序
以我设定的可执行程序myprocess为例
./myprocess  ->  ./  ->  当前路径 ->  找到程序

 ———— 我是一条知识分割线 ————

通过上面的图片我们可以知道,我们的指令文件是放在 /usr/bin/ 路径下的。那有朋友会问了,是不是直接将我自己的程序 cp(安装)到 /usr/bin/ 路径下就可以直接使用了呢?是的,但是不建议这么干。因为我们的代码没有经过测试,随意放入可能会造成指令池的污染。

那为什么系统能找到对应的运行程序 or 指令呢?原因是系统里面存在一个环境变量 PATH,PATH存储的是常见指令的搜索路径,当我们使用指令 ls时,系统会自动通过PATH环境变量,找到这个指令的位置并运行。注意:这个变量是系统定义的,每次打开shell的时候会恢复,全局有效。

echo $PATH - 打印指定命令的搜索路径(常见指令的默认搜索路径)

那我们要如何实现不用 ./ 就能运行自己的程序呢?相信大家已经猜到了,那就是将我们的文件路径添加到默认搜索路径里面。

下面我们来做一个演示,先创建一个循环打印 pid(进程id)的程序,使用 gcc编译之后生成了可执行程序 a.out,接下来的操作如下图所示。

export PATH=$PATH:可运行程序所在路径
  • export: 设置一个新的环境变量
  • 默认搜索路径下的冒号表示系统不同的路径相互区分
  • PATH=$PATH:/home/ldx,$PATH代表旧的PATH,后面:再跟自己程序的路径,这是为了避免原来的默认路径被自己程序的路径覆盖

最后我们发现,只需要输入 a.out这个程序就直接运行起来了


二、我的环境变量为什么会自己恢复

上面我们说到,环境变量是系统定义的,属于系统级变量,每次打开shell的时候会恢复,这又是怎么做到的呢?我们一起来看下面这个例子,我们设置一个 a本地变量,这是一个 bash变量赋值,大家可以思考一下,a变量是储存在哪里的呢?

实际上,a变量和其他本地 or 环境变量一样,会存放在一个专门存放变量的地方。在家目录下输入指令 ls -al,我们可以看到以下两个文件,这两个文件实际上是将环境变量导入shell中的脚本,当我们每次打开shell的时候,脚本都会运行一次,将环境变量从内存中导出同时还会给我们维护一些像 PATH之类的环境变量,因此即使我们修改了 PATH,下次打开 shell的时候会恢复

注意:本地变量不会恢复,不具有全局属性(我们在文章第七节会详细介绍)

[ldx@VM-12-11-centos ~]$ ls -al

-rw-r--r--   1 ldx  ldx    193 Apr  1  2020 .bash_profile
-rw-r--r--   1 ldx  ldx    351 Oct 25 16:53 .bashrc


三、环境变量的基本概念

  • 环境变量(environment variables)是操作系统为了满足不同应用场景,而预先在系统中设置的一大批的全局变量

如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

  • 环境变量通常具有某些特殊用途,且在系统当中通常具有全局特性

不同的环境变量对应不同的领域,有的可以帮助我们查找指令、有的可以确认登录用户是谁、有的是帮助我们确认主机名的等等

总结:这些操作系统为我们提供的,具有全局属性的,往往具备特殊功能的变量,我们称之为环境变量


四.常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
    • 我们常见的指令 cd ~, ~ 和 HOME 环境变量具有对应关系
  • LOGNAME:当前用户
  • SHELL : 当前Shell,它的值通常是/bin/bash。
  • HOSTNAME:主机名
  • HISTSIZE:Linux能记住的指令条数,通常为1000(可以通过上翻查看历史指令)
  • PWD - 记录当前路径的环境变量(后面第八节会有详细讲解)
history    #指令,可以查看所有历史指令


五.查看环境变量方法

1.查看所有环境变量

env    #查看所有环境变量

2.查看确定名称的环境变量

echo $PATH    #打印确定的环境变量,这里打印的是PATH变量

 ———— 我是一条知识分割线 ————

3.设置/读取本地变量方法

注意:本地变量不会恢复,不具有全局属性(我们在文章第七节会详细介绍)

(1)设置本地变量 

[ldx@VM-12-11-centos ~]$ myval=1234567   #设置myval本地变量

(2)读取/打印本地变量

[ldx@VM-12-11-centos ~]$ echo $myval    #读取/打印mycal环境变量
1234567
set | grep myval    #set指令可打印所有变量

(3)本地变量不可使用环境变量的方法查看

env | grep myval    #这种方法是不行的

 ———— 我是一条知识分割线 ————

4.设置/读取自定义环境变量方法

(1)定义一个环境变量

export命令:设置一个新的环境变量

export定义的环境变量,如果该本地变量已经存在,可通过 export+变量名 直接定义为环境变量

export myval    #定义一个名为myval的环境变量

自定义环境变量的另一种常见设置方法

export myval="you can see me"

(2)查看自定义环境变量

env | grep myval 
set | grep myval    #set指令可打印所有变量

 ———— 我是一条知识分割线 ————

5.清除环境变量方法

清除环境变量 myval(本地变量和环境变量都可以清除)

unset myval    #清除需要一些时间,不会立刻清除


 六、环境变量相关的命令汇总

  1. echo: 显示某个环境变量值
  2. export: 设置一个新的环境变量
  3. env: 显示所有环境变量
  4. unset: 清除环境变量
  5. set: 显示本地定义的shell变量和环境变量
history    #指令,可以查看所有历史指令


七、环境变量具有全局属性

环境变量通常具有全局属性,可以被子进程继承下去

为什么我们需要子进程继承环境变量呢?

我们知道,bash(命令行解释器)是一个系统进程,当我们在运行一个自定义程序时,程序也会变成一个进程,该进程为bash的子进程(通过fork实现)。当环境变量具有全局属性且可以被子进程继承时,自定义程序对应的子进程将可以满足很多不同的应用场景。

而我们之前说到的本地变量,则是只会在本进程(bash)内有效

举一个简单的例子,验证环境变量是可以被子进程继承

  • 我们可以创建一个名为 mycmd的文件,设计一段代码,验证某变量是否为环境变量。
  • 对于下面代码是如何获取环境变量的,这里我们暂时不用关心,我们在这里只需要明确一点,该程序运行起来后形成的进程,是 bash的子进程即可,其他的知识文章后边我们会有所提及。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define USER "USER"
#define MY_ENV "myval"


int main()
{
	char* myenv = getenv(MY_ENV);
	if (NULL == myenv)
	{
		printf("%s, not found\n", MY_ENV);
		return 1;
	}
	printf("%s=%s\n", MY_ENV, myenv);

	return 0;
}

 设置一个本地变量

[ldx@VM-12-11-centos ~]$ myval=1234567
  •  对mycal验证如下,
  • 我们发现程序获取不到 mycal变量,说明这个变量并不存在于该进程中,也就是说,它不存在于 bash的子进程中。

 

  ———— 我是一条知识分割线 ————

 使用export,定义环境变量

export myval    #定义一个名为myval的环境变量
  • 运行 mycmd,得出实验结果

  • 再次运行程序,你可以发现结果有了!

说明:环境变量是可以被子进程继承下去的!因为 mycmd作为一个自定义程序,生成的对应进程是bash的子进程,但是它却可以读取到来自于父进程的环境变量 myval


八、PWD - 记录当前路径的环境变量

前面我们已经学习了为什么指令作为一个可执行程序不需要加 ./ 运行的原因,那就是是系统里面存在一个环境变量 PATH,PATH存储的是常见指令的搜索路径,当我们使用指令 ls时,系统会自动通过PATH环境变量,找到这个指令的位置并运行。

那么问题来了,下面的指令,为什么可以运行呢?你知道 ls的地址也就罢了,你凭什么又知道Makefile的地址?

ls Makefile    #可以运行
ls ./Makefile    #可以运行,为什么不用这样输入

那是因为系统中存在一个 PWD变量,该变量主要用于记录当前路径。环境变量是被 bash维护的,每当我们的路径变化的时候,我们的 shell会自动帮我们调整 PWD环境变量。当我们使用 ls指令的时候,由于 ls是一个 bash的子进程,环境变量被子进程继承之后,ls就知道自己在哪个路径下,所以就可以实现上面的代码。

至此,我们就知道了为什么我们平时查询文件的时候不用带 ./了。

 PWD的代码实现,getenv的知识我们将在下一章讲解。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MYPWD "PWD"


int main()
{
	printf("%s\n", getenv(MYPWD));

	return 0;
}

将编译之后的可执行代码文件添加默认搜索路径下,可以实现直接输入文件名运行。

export PATH=$PATH:可运行程序所在路径


九、在进程上下文中,获取环境变量的三种方式

  • getenv
  • char *enc[ ]
  • extern char** environ

1.getenv获取环境变量

getenv获取环境变量,创建一个文件写入当前代码

  • 需要包含头文件 #include <stdlib.h>
  • 下述代码中的 #define USER “USER”的含义为将环境变量USER定义为USER

通过实验我们可以发现,不同用户运行这段相同代码时,输出的结果不同。因此我们可以知道,环境变量USER随用户改变而改变,它具有标识当前Linux用户的功能。

  ———— 我是一条知识分割线 ————

接下来,我们再修改一下代码,使用 strcmp函数进行比对,就可以实现特定用户的特定信息输出。如果用普通用户运行下述代码,会输出权限不足;而root用户则可以正常打印user。

由此,我们就可以知道,我们在电脑上为什么在进行某些操作的时候会出现权限不足、无法正常运行的提示。同时我们也可以知道,他们大致的底层原理是怎么样的了。

注:Linux下很多指令都是会进行身份认证的,其中很多会使用 USER环境变量进行检测,例如我们常见的 cd命令,root用户可以进入普通用户的家目录,而一个普通用户不能进入其他普通用户的家目录,除非进行权限提升。

2.char *enc[ ]获取环境变量

main函数()里面的参数称为命令行参数,命令行参数最多有3个。

我们建立一个 mycmd文件,写入下述代码并编译

int main(int argc, char *argv[])//char *argv[]指针数组,构建命令行参数表,记录函数名和对应选项
{
	for (int i = 0; i < argc; i++)
	{
		printf("argv[%d]->%s\n", i, argv[i]);
	}
	return 0;
}

通过命令行参数,我们可以依次将程序名和对应的选项(a/b/c)传递给 argv(通过指针数组储存选项,用空格将选项隔开)。

注意:有些朋友的gcc版本比较低的话,可能无法编译,需要在 makefile文件中加上 -std=c99,才能实现编译。

   ———— 我是一条知识分割线 ————

通过命令行参数我们具有了获取程序名和对应选项的能力,只需要我们修改代码的内容,就可以实现在一个程序后面添加不同的选项,系统就帮我们实现不同的功能。

int main(int argc, char *argv[])
{
	if (argc != 2)
	{
		printf("Usage: \n\t%s [-a/-b/-c/-ab/-bc/-ac/-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;
}

运行结果如下 

 这样就实现了同一个程序后面跟不同的选项,就实现不同的功能。

注意:这是通过它的命令行选项决定的

———— 我是一条知识分割线 ————

实际上,环境变量就是字符串。在我们输入指令回车运行的时候,系统会为我们传两张表,它们分别是:命令行参数表,环境变量表命令行参数表获取程序名和对应选项环境变量表获取进程对应的环境变量,环境变量表以 NULL结尾

通过运行下面的代码,可以打印所有进程的环境变量

#include <stdio.h>
int main(int argc, char* argv[], char* env[])//char* env[]指针数组,构建环境变量表,记录进程对应的环境变量
{
	int i = 0;
	for (; env[i]; i++) {
		printf("%s\n", env[i]);
	}
	return 0;
}

3.extern char** environ获取环境变量

除了上面获取进程环境变量的方法还有别的方法吗?答案是有的,我们可以通过第三方变量environ获取环境变量。

environ是一个系统用C语言为我们编写好的对应 char env[] 数组的变量。

环境变量表对应的结构为 char* env[],它是一个一级指针,实质上为 char*,所以我们可以用一个char**的指针去储存 char*。

通过运行下面的代码,可以打印所有进程的环境变量

#include <stdio.h>
int main(int argc, char* argv[])
{
	extern char** environ;    //关键字extern,标识后可以在一个文件中引用另一个文件中定义的变量或者函数,说明该变量在系统中存在
	int i = 0;
	for (; environ[i]; i++) {
		printf("%s\n", environ[i]);
	}
	return 0;
}

总结:为了使用需要,我们更多的使用 getenv() 这种方法获取环境变量


 🌹🌹Linux环境变量的知识大概就讲到这里啦,博主后续会继续更新更多Linux操作系统的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪 

  • 27
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值