【Linux】环境变量
目录
- 背景
- 1.概念
- 2.常见环境变量
- 2.1 PATH
- 指令和自定义程序
- 向环境变量PATH中添加路径
- 删除PATH中的路径
- 2.2 env:显示所有环境变量
- 2.3 环境变量相关的命令
- 3.通过代码获取环境变量
- 1.char* envp[]
- 2.第三方变量enciron
- 3.getenv函数获取指定环境变量
- 4.利用获取的环境变量
- 自制pwd
- 限制文件执行对象
- 4.环境变量来自哪里
- .bash_profile
- .bashrc
- /etc/bashrc
- 5.环境变量的全局性
- 全局性
- 6.环境变量总结
- 7.main函数的前两个参数
背景
大家在学习Java或Pathon亦或安装某个软件时,大多经历过要修改环境变量的情况,那环境变量是什么?下面让我们一起来揭开环境变量 的神秘面纱。

1.概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 当我们在编写C/C++代码时,在链接时,我们从来不知道所链接的动态库在哪,但是照样可以链接成,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊的用途,还有在系统当中通常具有全局特性。
2.常见环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录(即用户登录到Linux系统中时,默认的目录)
- SHELL:当前Shell,它的值通常是
/bin/bash
- USER:存放当前用户的用户名
通常我们使用echo $NAME
来查看对应的环境变量内容(NAME:环境变量名)
- PATH中各路径使用冒号 : 分隔
2.1 PATH
首先,我们创建test.c 文件,编写如下代码
其次,创建makefile 文件,编写如下代码
当我们完成相应的操作,使用make
指令创建对应的可执行文件myprocess ,当我们想要执行这个可执行文件需要使用./myprocess
,那我们可不可以直接使用myprcess
来执行呢?答案当然是不行,那要则没做才能办到呢?这就和环境变量有关了。
指令和自定义程序
在Linux中,我们使用指令(如:ls)来操作系统,而指令也是使用C写的,放在系统的某个位置,和我们写的程序是没有区别的,这里我们使用file
指令来查看ls
和myprocess
的区别
我们从上图可以看到,指令和我们写的程序是没有区别的,这些指令就是一个个已经写好的可执行文件。
我们通常想要执行一个可执行文件需要使用绝对路径或相对路径来定位需要执行文件的位置
- 相对路径:
./
,其中.
表示当前路径,/
为路径分隔符- 绝对路径:
home/../../可执行文件
所以,想要执行一个可执行文件,就需定位它的路径,而我们使用的指令之所以不用带路径就能执行,是因为它被纳入到基本指令的范畴,路径已经实现被放到了环境变量PATH
中,如下图
每当我们使用指令完成某个操作,系统就会从左向右,找到环境变量中对应的路径,执行该指令的可执行文件。
了解了这些,我们就有两个方法使得我们的可执行文件,不使用路径直接运行。
- 将可执行文件放入已经在环境变量中的某个路径下(会有权限限制,需在root用户下执行或sudo提权)
- 将可执行文件对应的路径添加到PATH 环境变量中
这里我们只讲第二种方法。
向环境变量PATH中添加路径
使用下面的指令来完成路径的添加:
export PATH=$PATH:对应的路径
- 其中,是将
$PATH:对应的路径
赋值给PAT,新的值会覆盖原有的值,$PATH
代表PATH中的原路径,使用:
分割,之后是添加的新路径
如下图,向PATH环境变量 中添加myprocess 可执行文件的对应路径,之后查看PATH是否修改
此时我们就在该目录下创建的可执行文件,即可只使用文件名运行了
删除PATH中的路径
下面的指令表示为PATH重新赋值,将之前的值覆盖
export PATH=对应的路径
比方说,PATH中的路径如下:
路径1:路径2:路径3:路径4
我们想要删除路径4 ,只需复制路径1:路径2:路径3,之后复制给PATH即可
export PATH=路径1:路径2:路径3
我们使用该方法删除上面添加的路径,如下图
注意:
若使用
export PATH=..
时使用错误,覆盖了原来的所有路径,重启终端(关闭shell,重新启动)即可。也就是说,我们进行PATH的配置只在本次登录有效,当重启后,我们添加的路径就会消失,变为原本系统默认的路径。如果想要可执行文件永久使用文件名运行,需要将其移至永久有效的路径下,相同的删除也只能删除路径下对应的文件。(拷贝和删除文件时有权限限制)
2.2 env:显示所有环境变量
我们可以使用env
指令,显示所有的环境变量,如下:
其中:
-
HOSTNAME:表示这台机器的主机名
-
HISTSIZE:表示保留之前指令的最大数量
我们想要看到命令行中输入的历史命令可以使用
history
指令,但操作系统不会将我们所写的指令都保存下来,只会保留最新的HISTSIZE
个历史指令 -
SSH_CLIENT:表示当前是那台主机在登录我们的Luinux机器
-
USER:当前登录用户
我们创建一个文件或是目录,创建后它的所属组和拥有者都是根据USER来给定的
- 使用
su
指令切换用户,USER不会发生改变 - 使用
su -
指令切换用户,USER会发生改变
- 使用
-
LS_COLOR:配色方案
当我们使用某些指令时,会发现一些数据的颜色区别于其它数据,这就是由LS_COLOR指定的
-
PWD:确认当前用户所在的路径
我们使用
pwd
指令获取当前所在位置时,使用的就是这个环境变量 -
HOME:表示当前用户所在的家目录
不同的用户,HOME值不同
-
LOGNAME:表示登录的用户
- 使用
su
指令切换用户,LOGNAME不会发生改变 - 使用
su -
指令切换用户,LOGNAME会发生改变
- 使用
- 环境变量是根据特定的人在特定的场景中使用的
2.3 环境变量相关的命令
- echo: 显示某个环境变量值(在环境变量名前加$符)
- export: 设置一个新的环境变量
- env: 显示所有环境变量
- unset: 清除环境变量
- set: 显示本地定义的shell变量和环境变量
3.通过代码获取环境变量
C/C++代码,main函数是程序的入口,,main函数可以接收参数,最多可以接收三个或是两个参数,写法如下:
int main(int argc,char* argv[],char* envp[])
{}
- 编译器在编译时会自动传递这三个参数,只是我们不用而已
- 其中,也可以只接收前两个参数,最后一个不写,我们这里先来讲最后一个参数
char* enpv[]
,知道这个剩下两个就好理解了。 - 我们的进程内部本身就有环境变量,这需要我们去获取(下面就是获取方式)
1.char* envp[]
envp为指针数组,main函数的第三个参数,存放指针,指针对应的数据为环境变量(执行一个额一’\0’结尾的环境字符串),第一个无效内容指向NULL
这里我们要区分两个概念:
- 指针:表示地址,凡是具有指向能力的数据都叫指针
- 指针变量:表示变量,在内存中开辟空间,具有存储和被修改的能力
envp指针数组存放的是指针,指针的类型为char,指向字符串或字符,这里的envp是指向字符串,也就是环境变量。
我们将test.c 文件修改如下:
其中,当envp[i]
为NULL时表示有效数据已经循环完毕
将makefile文件修改如下:
使用make
指令生成可执行文件,之后运行,得出下面的结果
输出的正是环境变量,我们可以通过该方法在我们自己写的程序内获取环境变量。
2.第三方变量enciron
除了main函数的第三个参数,我们还可以使用libc中定义的全局变量environ 指向环境变量表,来获取环境变量。
注意:
- environ没有包含在如何头文件内,在使用时要用extern声明,表示为外部变量。
- environ为二级指针,相当于指针数组指向环境变量表
将test.c 修改如下:
使用make指令生成对应的可执行文件,之后执行该文件,获得如下结果
我们依然可以看到,使用该方法就可以获得环境变量。
问题:
我们已经知道可以通过main函数的第三个参数或二级指针environ变量获取环境变量,然后呢?难道我们要用的时候只能通过遍历环境变量表来获取想要的环境变量吗?这是不是太麻烦了?
这样做在我们想要获取某一环境变量时却是i不方便,所以,我们在实际操作中最常用的是下面要讲的函数获取环境变量,想要什么环境变量直接告诉函数,通过它来获取。
3.getenv函数获取指定环境变量
通过向getenv函数传递想要获得的环境变量的环境变量名来获取,该函数头文件为**<stdlib.h>**
格式:
char* 变量名 = getenv("环境变量名");
我们通过下面的代码来演示,获取USER的环境变量,其它的环境变量也是一样的
首先,将test.c 文件修改如下:
使用make指令生成可执行文件,执行该文件获取如下结果:
- 想要获取其它的环境变量也是使用相同的方法
4.利用获取的环境变量
现在我们既然可以获取到环境变量了,那我们该用它来做什么呢?下面通过两个例子来向大家介绍一二
自制pwd
我们可以自己写一个程序,来获取当前所处的位置,如下:
首先,再次将test.c 文件修改如下:
使用make指令生成可执行文件后执行它,获取如下结果:
我们还可以将该可执行文件的路径放在PATH环境变量下,在为其改名为mypwd ,这样我们在如何地方都可以执行它,如下:
限制文件执行对象
若一个可执行文件,我们只想要让自己或其它指定用户使用,我们可以依靠环境变量做出限制
首先,再次将test.c 文件修改如下:
注意:该程序用到strcmp函数,该函数需要引用string.h 库
其次,使用make指令生成可执行文件,在两个用户下执行该文件,查看结果
用户YX
root用户
- 注意:这里要使用
su -
来切换到root用户的家目录,在到可执行文件的目录下运行该文件,才可以看到效果。否则对应的USER环境变量不会改变
4.环境变量来自哪里
环境变量是我们登录LInux系统后,在对应用户的家目录 下的
.bash_profile
和.bashrc
两个配置文件中获取的
.bash_profile
打开.bash_profile
文件查看其内容
在我们登录成功后,系统会调用该配置文件,执行其内容,调用.bashrc
配置文件,加载配置文件PATH
环境变量得以添加。
.bashrc
在打开.bashrc
文件查看其内容
/etc/bashrc
- 存放全局的环境变量
总结:
登录系统后,系统会调用对应用户家目录下的.bash_profile
配置文件,.bash_profile
配置文件中又调用同目录下.bashrc
配置文件,而.bashrc
配置文件又调用/etc/bashrc
配置文件,生成环境变量。
5.环境变量的全局性
环境变量本质就是一个内存级的一张表,这张表由用户在登录系统时,进行给特定用户形成属于自己的环境变量表。而环境变量通常具有全局属性,可以被子进程继承下去。
我们先来看一下下面的两种情况:
情况1:
我们在命令行中编写一个变量,并为它赋值,之后使用echo
指令取出
情况2:
在命令行编写变量并为它赋值时使用export
指令修饰,使其变为环境变量,之后使用env
指令查看
大家或许都知道这两种现象的存在,但对于它为什么存在却知之甚少,原因如下:
情况1
系统启动后,它的shell也是一个进程在内存内有自己的一块空间,用来存储环境变量表或是读取到的命令等等,当我们在命令行中写下字符串mynum=100 后,会在它的上下文中使用malloc 开辟一块空间,用来存放对应的字符串,如下图:
- 此时被shell存下的变量叫做本地变量,只在shell的内部有效
情况2:
当我们使用
export
指令后,系统会在环境变量表的第一个无效的内容处存放export
后的字符串,或者可以理解为在环境变量表中使用malloc 开辟一块空间存放字符串
全局性
我们在Linux中使用指令或是执行可执行文件都是创建子进程的过程,而这些子进程的父进程都是shell,在子进程创建时,shell会将自己内部维护的环境变量表传给子进程,使其也可以使用环境变量,这就是环境变量通常具有全局属性,可以被子进程继承下去。
证明如下:
将test.c 文件修改如下:
使用make
指令生成对应的可执行文件,并执行,结果如下:
通过上图,我们看到在命令行中我们设置的环境变量mynum=50 在子进程中依然可以得到,父进程的确将环境变量交给了子进程。
证明:环境变量是可以被子进程继承下去的!
6.环境变量总结
- 环境变量本质就是一个内存级的一张表,这张表由用户在登录系统时,进行给特定用户形成属于自己的环境变量表。
- 环境变量是由shell维护的,创建子进程后shell会使用一些方法将其传给子进程,证明环境变量具有全局属性。
- 环境变量中的每一个,都有自己的用途,有的是进行路径查找的,有的是进行身份认证的,有的是进行动态库查找的,有的是用来进行确认当前路径等等。
- 每个环境变量都有自己独特的应用场景。
- 每一个环境变量都有自己的名字和内容。
- 环境变量都是从相关配置文件中读取出来的(所以每次登录环境变量是相同的,在家目录下的
.bash_profile
和.bashrc
中)
7.main函数的前两个参数
main函数是可以接收三个参数的,最后一个是接收env环境变量表的,而前两个是可以单独写的,用来接收选项 。
int main(int argc,char* argc[],char* envp[])
我们在执行指令时经常后待一些参数,比如使用ls
指令时,会使用-l、-a
等参数
而ls
也是一个可执行文件,该文件所在位置存放在环境变量PATH
中,我们可以不去管它的位置,直接使用文件名即可运行,既然是可执行文件,那它对应的程序中一定有main函数,它main函数中的前两个参数就是用来接收,命令行中输入的选项的。
int main(int argc,char* argv[])
- argv:存放命令行中传入的选项的地址(包含可执行程序这个字符串),第一个无效字符存放NULL
- argc:表示传入的选项个数
接下来,我们来测试一下:
先将test.c 文件修改如下:
接着,使用make
指令,生成可执行文件,执行如下指令
我们看到,父进程bash将命令行中的字符串使用空格分割,传给子进程main函数的argv 参数。
- 这就是我们在使用指令时,对应的程序识别选项的方法原因。
我们接下来写一个小程序,来模拟选项的实现:
将test.c 文件修改如下,功能为,只向可执行程序传输一个选项(不包含可执行文件名),执行对应的操作,若一个没有则返回一段提示,告诉用户需传输选项:
使用make
指令,执行可执行文件,对其进行测试,如下:
相关文章:

【Linux】环境变量
目录背景1.概念2.常见环境变量2.1 PATH指令和自定义程序向环境变量PATH中添加路径删除PATH中的路径2.2 env:显示所有环境变量2.3 环境变量相关的命令3.通过代码获取环境变量1.char* envp[]2.第三方变量enciron3.getenv函数获取指定环境变量4.利用获取的环境变量自制…...
单一职责原则
单一职责原则: 就一个类而言,应该只有一个引起它变化的原因,如果一个类承担的职责过多就等于把这些职责耦合在一起,至少会造成以下两方面的问题: 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合…...

golangの并发编程(GMP模型)
GMP模型 && channel1. 前言2. GMP模型2.1. 基本概念2.2. 调度器策略2.3. go指令的调度流程2.4. go启动周期的M0和G02.5. GMP可视化2.6. GMP的几种调度场景3. channel3.1. channel的基本使用3.2. 同步器1. 前言 Go中的并发是函数相互独立运行的体现,Gorouti…...

MacBook Pro错误zsh: command not found: brew解决方法
问题描述:本地想安装Jenkins,但是brew指令不存在/我的电脑型号是19款的MacBook Pro(Intel芯片)。解决方法MacBook Pro 重新安装homebrew,用以下命令安装,序列号选择阿里巴巴下载源。/bin/zsh -c "$(cu…...

spring中BeanFactory 和ApplicationContext
在学习spring的高阶内容时,我们有必要先回顾一下spring回顾spring1.什么是springspring是轻量级的,指核心jar包时很小的;非侵入式的一站式框架(数据持久层,web层,核心aop),为了简化企业级开发。核心是IOC&a…...
HC32L17x的LL驱动库之dma
#include "hc32l1xx_ll_dma.h"/// //函 数: //功 能: //输入参数: //输出参数: //说 明: // uint8_t LL_DMA_DeInit(DMA_TypeDef* DMAx, uint32_t Channel) {__IO uint32_t* dmac NULL;dmac &(DMAx->CONFA0);Channel << 4;dmac …...

SSM项目 替换为 SpringBoot
一、运行SSM项目 保证项目改为SpringBoot后运行正常,先保证SSM下运行正常。 项目目录结构 创建数据库,导入sql文件 查看项目中连接数据jar版本,修改对应版本,修改数据库配置信息 配置启动tomcat 运行项目,测试正常…...
RL笔记:动态规划(2): 策略迭代
目录 0. 前言 (4.3) 策略迭代 Example 4.2: Jack’s Car Rental Exercise 4.4 Exercise 4.5 Exercise 4.6 Exercise 4.7 0. 前言 Sutton-book第4章(动态规划)学习笔记。本文是关于其中4.2节(策略迭代)。 (4.3) 策略迭代 基…...

2023软件测试金三银四常见的软件测试面试题-【测试理论篇】
三、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段:需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的SE会把需求文档给我们自己先去了解一到两天这样,之后我们会有一个需求澄清会议, 我…...
蓝桥训练第二周
1 ,泛凯撒加密 内存限制:128 MB时间限制:1.000 S 题目描述 众所周知,在网络安全中分为明文和密文,凯撒加密是将一篇明文中所有的英文字母都向后移动三位(Z的下一位是A),比如a向后…...

详讲函数知识
目录 1. 函数是什么? 2. C语言中函数的分类: 2.1 库函数: 2.2 自定义函数 函数的基本组成: 3. 函数的参数 3.1 实际参数(实参): 3.2 形式参数(形参): …...

gin 框架初始教程文档
一 、gin 入门1. 安装gin :下载并安装 gin包:$ go get -u github.com/gin-gonic/gin2. 将 gin 引入到代码中:import "github.com/gin-gonic/gin"3.初始化项目go mod init gin4.完整代码package mainimport "github.com/gin-go…...

Maven的下载和安装【详细】
文章目录一、什么是Maven?二、Maven的安装与配置2.1下载Maven安装包2.2配置Maven环境变量2.3验证三、Idea配置Maven3.1配置 setting.xml文件3.2Idea配置Maven一、什么是Maven? Apache Maven是个项目管理和自动构建工具,基于项目对象模型&…...

[数据结构]:04-循环队列(数组)(C语言实现)
目录 前言 已完成内容 循环队列实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-QueueCommon.cpp 04-QueueFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为C语言代码。使用C引用主要是为了…...

buu [GWCTF 2019]BabyRSA 1
题目描述: import hashlib import sympy from Crypto.Util.number import *flag GWHT{******} secret ******assert(len(flag) 38)half len(flag) / 2flag1 flag[:half] flag2 flag[half:]secret_num getPrime(1024) * bytes_to_long(secret)p sympy.nextp…...
codeforces 1669F
题意: alice和bob从数组两边的吃糖果, 数组的值就是糖果重量 要求alice和bob吃的糖果重量必须一样, 输出能吃几个糖果 这题最先想到的是前后缀相加 模拟一个前缀和 和 后缀和 在n/2的位置向前找前缀和 在n/2的位置向后找后缀和 找到第一个前缀和后缀和的下标输出就好 …...
高数考试必备知识点
三角函数与反三角函数的知识点 正弦函数 ysin x, 反正弦函数 yarcsin x • y sin x, x∈R, y∈[–1,1],周期为2π,函数图像以 x (π/2) kπ 为对称轴 • y arcsin x, x∈[–1,1]…...

[蓝桥杯] 二分与前缀和习题练习
文章目录 一、二分查找习题练习 1、1 数的范围 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 机器人跳跃问题 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 四平方和 1、3、1 题目描述 1、3、2 题解关键思路与解答 二、前缀和习题练习 2、1 前缀和 2、1、1 题目描述…...

SpringMvc中HandlerAdapter组件的作用
概述 我们在使用springMVC时,都知道其中不仅包含handlerMapping组件还包含handlerAdapter组件,为什么呢? springMVC请求流程图 HandlerAdapter组件使用了适配器模式 适配器模式的本质是接口转换和代码复用,这里使用适配器模式的…...

FreeRTOS优先级翻转
优先级翻转优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。
2024 年,高端封装市场规模为 80 亿美元,预计到 2030 年将超过 280 亿美元,2024-2030 年复合年增长率为 23%。 细分到各个终端市场,最大的高端性能封装市场是“电信和基础设施”,2024 年该市场创造了超过 67% 的收入。…...