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

news2024/9/22 23:30:28

 🌟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操作系统的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/511002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Acwing456. 车站分级

一条单向的铁路线上&#xff0c;依次有编号为 1, 2, …, n的 n 个火车站。 每个火车站都有一个级别&#xff0c;最低为 1 级。 现有若干趟车次在这条线路上行驶&#xff0c;每一趟都满足如下要求&#xff1a;如果这趟车次停靠了火车站 xx&#xff0c;则始发站、终点站之间…

【网络】-- 数据链路层

应用层&#xff08;http、https&#xff09;&#xff1a; 数据的使用。传输层&#xff08;UDP、TCP&#xff09;&#xff1a;网络通讯的细节&#xff0c;将数据可靠的从A主机跨网络送到B主机。网络层&#xff08;IP&#xff09;&#xff1a;提供一种能力&#xff0c;将数据从A主…

Real-ESRGAN:Training Real-World Blind Super-Resolution with Pure Synthetic Data

https://github.com/NightmareAI/Real-ESRGAN/tree/masterhttps://github.com/NightmareAI/Real-ESRGAN/tree/master从SRCNN到EDSR&#xff0c;总结深度学习端到端超分辨率方法发展历程 - 知乎超分辨率技术&#xff08;Super-Resolution, SR&#xff09;是指从观测到的低分辨率…

设计模式MVC、MVP、MVVM

MVC、MVP和MVVM是什么&#xff1f; MVC&#xff1a;Model-View-Controller&#xff0c;是一种分层解偶的框架&#xff0c;Model层提供本地数据和网络请求&#xff0c;View层处理视图&#xff0c;Controller处理逻辑&#xff0c;存在问题是Controller层和View层的划分不明显&am…

SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中)

场景 SpringBootValidated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例&#xff1a; SpringBootValidated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例_validated 怎么设置boolean类型非空_霸道流氓气质的博客-…

Elasticsearch02

目录 Elasticsearch02DSL查询文档查询所有全文检索查询精确查询地理查询复合查询 搜索结果处理排序分页高亮 DSL总结RestClient查询文档快速入门:match_all查询match查询精确查询布尔查询排序、分页高亮 实战案例HotelControllerIHotelServiceHotelMapperHotelHotelDocPageResu…

Google SEO优化的10大误区

以下是 Google SEO 优化的十大误区&#xff1a; 1、关键词堆砌&#xff1a; 过度使用关键词&#xff0c;使得内容不自然&#xff0c;难以阅读&#xff0c;同时也会被搜索引擎认为是垃圾信息&#xff0c;影响网站排名。 2、内容质量差&#xff1a; 质量差的内容会降低用户的体…

矩池云上配置FusionGan环境

1、租赁环境 2、vscode 连接 矩池云 教程&#xff1a;https://www.matpool.com/supports/doc-vscode-connect-matpool/ 3、进入mnt文件夹 cd ../mnt 4、克隆代码 git clone https://github.com/jiayi-ma/FusionGAN.git 如果克隆不下来&#xff0c;就自己下载&#xff0c;…

ESP32 DW1000 UWB 室内定位系统

相关软件代码下载》》 概述 在这个项目中,我们将制作一个基于 ESP32 DW1000 UWB 的室内定位系统。为此,我们将使用 2 个 UWB 锚点和 1 个 UWB 标签。当标签移动时,UWB 标签的实时位置可以使用Python 程序在PC 上以图形方式显示。 工业环境中的室内跟踪通常需要非常精确的…

C++引用的相关定义以及使用场景与指针之前的区别

一、引用的定义与特性 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 引用的特性&#xff1a; 引用在定义时必须初始化一个变量可以有多个引用引用一旦引用…

电脑技巧:宽带怎么设置教程笔记,看完你就会了

宽带的设置是指将计算机连接到互联网的过程。一般来说&#xff0c;宽带的设置是非常简单的&#xff0c;只需要按照提供商的要求&#xff0c;正确地连接硬件和软件就可以了。下面将详细介绍如何设置宽带。 硬件设置&#xff1a;首先&#xff0c;需要连接计算机和调制解调器&…

sharding-jdbc读写分离实战

一、读写分离介绍 Sharding-JDBC读写分离则是根据SQL语义的分析&#xff0c;将读操作和写操作分别路由至主库与从库。它提供透明化读写分离&#xff0c;让使用方尽量像使用一个数据库一样使用主从数据库集群。 为了实现Sharding-JDBC的读写分离&#xff0c;首先&#xff0c;要…

Leetcode2404. 出现最频繁的偶数元素

Every day a Leetcode 题目来源&#xff1a;2404. 出现最频繁的偶数元素 解法1&#xff1a;哈希 我们构建一个这样的哈希表 unordered_map<int, int> umap&#xff1a; key&#xff1a;偶数数组元素 nums[i]value&#xff1a;nums[i]的出现次数 count 我们遍历一次数…

算法之路--快速排序算法

由于冒泡算法算法之路--冒泡算法&#xff08;算法之路--冒泡算法&#xff09;每轮都要进行从头到落位之前的每个元素的比较&#xff0c;在执行效率上需要提升&#xff0c;快速排序算法就是对冒泡算法的一种效率上的提升。 算法思路 快速排序是基于冒泡的改进&#xff0c;所以基…

力扣回溯算法专题(二)- 切割 子集问题 131.分割回文串、93. 复原IP地址、78. 子集、90. 子集Ⅱ、491.递增子序列 思路 C++实现 总结

文章目录 切割问题子集问题回溯法模板与伪代码131. 分割回文串三要素及思路回文字符串判断代码 93. 复原IP地址三要素及思路验证子串是否合法代码 78. 子集三要素及思路代码 90. 子集Ⅱ三要素及思路三种去重方式代码 491.递增子序列三要素及思路去重方式及去重优化代码 总结1. …

Django框架004:orm对mysql的增删改查

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

TypeScript 配置简述

TypeScript 配置简述 初始化项目的过程为&#xff1a; 新建一个项目 这里使用 yarn init -y 去创建一个 node 项目&#xff0c;随后使用 yarn add typescript 下载 TS 的依赖 新建一个 ts 文件 console.log(test);随意 log 一点东西进行测试 使用 tsc 编译 ts 文件 ❯ yarn …

为什么国外资深的软件测试多是手动测试,但在国内,都推崇自动化测试?

将自动化测试当成很了不起的资本&#xff0c;源于国内对Coding的崇拜 譬如一个Dev跟一个QA放在一起&#xff0c;大家的第一直观印象就是——前者的技术能力比较强。 实际上&#xff0c;这个问题分两面看&#xff1a; 自动化测试能力是不是资本&#xff1f; 当然是。 测试自动…

redis(7)

全局ID生成器: 全局ID生成器&#xff0c;是一种在分布式系统下用来生成全局唯一ID的工具&#xff0c;一般要满足以下特性 唯一性高可用(随时访问随时生成)递增性安全性(不能具有规律性)高性能(生成ID的速度快) 为了增加ID的安全性&#xff0c;我们不会使用redis自增的数值&am…

yolov4

1 V4版本概述 集各种优秀方案于一身&#xff0c;嫁接了众多主流的目标识别方面的情况。 V4 贡献 3. 数据增强策略分析 BOF Bag of freebies(BOF) Mosiac 数据增强 Mixup 比如将狗和猫的两张图片混合&#xff0c;一半猫&#xff0c;一半狗。 label 也变成 Dog 0.5 , Cat 0…