<Linux>环境变量
创始人
2025-05-31 16:30:19

环境变量

在这里插入图片描述

文章目录

  • 环境变量
    • 一、基本概念
    • 二、常见环境变量
    • 三、查看环境变量的方法
    • 四、测试PATH
    • 五、测试HOME
    • 六、测试SHELL
    • 七、环境变量相关的命令
    • 八、环境变量的组织方式
    • 九、命令行参数
    • 十、通过代码获得环境变量
    • 十一、通过系统调用获取环境变量
    • 十二、环境变量通常是具有全局属性的

一、基本概念

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。

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

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

我们都清楚自己写的一串代码,经过编译后生成可执行程序,我们用./即可运行,但是系统里有些命令也是64位的可执行程序:

image-20230315154439285

  • 既然都是程序,那就可以把你自己的写的程序叫做指令,把系统的指令叫做命令程序or二进制文件。所以自己写的程序和系统中的指令没区别,均可以称为指令、工具、可执行程序。

二、常见环境变量

  • PATH: 指定命令的搜索路径。
  • HOME: 指定用户的主工作目录(即用户登录到Linux系统中的默认所处目录)。
  • SHELL: 当前Shell,它的值通常是/bin/bash。

三、查看环境变量的方法

我们可以通过echo命令来查看环境变量,方式如下:

echo $NAME //NAME为待查看的环境变量名称

例如,查看环境变量PATH。

echo $PATH

image-20230313140531288

四、测试PATH

大家有没有想过这样一个问题:为什么执行ls命令的时候不用带./就可以执行,而我们自己生成的可执行程序必须要在前面带上./才可以执行?
image-20230313140124450
容易理解的是,要执行一个可执行程序(指令)必须要先找到这个程序,既然不带./就可以执行ls命令,说明系统能够通过ls名称默认帮助我们找到ls的位置,而系统是无法找到我们自己的可执行程序的,所以我们必须带上./,以此告诉系统该可执行程序位于当前目录下。

而系统就是通过环境变量PATH来找到ls命令的,查看环境变量PATH我们可以看到如下内容:
image-20230313140531288
可以看到环境变量PATH当中有多条路径,这些路径由冒号隔开,当你使用ls命令时,系统就会查看环境变量PATH,然后默认从左到右依次在各个路径当中进行查找。
而ls命令实际就位于PATH当中的某一个路径下,所以就算ls命令不带路径执行,系统也是能够找到的。
image-20230313213901927

那可不可以让我们自己的可执行程序也不用带路径就可以执行呢?

当然可以,下面给出两种方式:

方式一:将可执行程序拷贝到环境变量PATH的某一路径下
既然在未指定路径的情况下系统会根据环境变量PATH当中的路径进行查找,那我们就可以将我们的可执行程序拷贝到PATH的某一路径下,此后我们的可执行程序不带路径系统也可以找到了。

sudo cp myproc /usr/bin/

image-20230313224352366

但是并不建议把你自己写的可执行程序随意添加到系统里,因为我们写的程序没有经过测试,可能会污染指令池。我们执行下面的命令删除即可:

sudo rm /usr/bin/myproc

方式二:使用exprot命令将可执行程序所在的目录添加到环境变量PATH中
将可执行程序所在的目录导入到环境变量PATH当中,这样一来,没有指定路径时系统就会来到该目录下进行查找了。

export PATH=$PATH:/home/wei/106/linux/lesson13

image-20230313225544091
将可执行程序所在的目录添加到环境变量PATH当中,并且在后面追加myproc的当前路径。位于该目录下的可执行程序也就可以在不带路径的情况下执行了。PATH中不能由空格,因为Linux中以空格为分隔符。
image-20230313225610123

如果想删除这个环境变量的话,执行【unset】命令。

我们通过下图也能发现:命令行可以定义本地变量和环境变量。

image-20230315145856194

学过Java的同学应该都知道,我们在最开始学习Java时需要在Windows中配置环境变量,其实其本质就是向PATH中添加内容 (Windows中的路径以分号分割)

image-20230314003717582

五、测试HOME

任何一个用户在运行系统登录时都有自己的主工作目录(家目录),环境变量HOME当中即保存的该用户的主工作目录。

普通用户示例:
image-20230314000315067
超级用户示例:
image-20230314000333565

六、测试SHELL

我们在Linux操作系统当中所敲的各种命令,实际上需要由命令行解释器进行解释,而在Linux当中有许多种命令行解释器(例如bash、sh),我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释器的种类。
image-20230314000443702
而该命令行解释器实际上是系统当中的一条命令,当这个命令运行起来变成进程后就可以为我们进行命令行解释。
image-20230314000554483

环境变量是怎么来的
我们 “ls -al /home/wei” 可以发现家目录下存在两个隐藏文件 – .bash_profile 与 .bashrc:

image-20230314005645965

.bash_profile

image-20230314010008732

.bashrc

image-20230314010046459

实际上,当我们在登录 shell 时,操作系统会让我们当前的 shell 进程执行 .bash_profile 中的内容,而 .bash_profile 又会调用执行 .bashrc,它们会将对应的环境变量导入到 shell 进程的上下文环境中。所以,如果我们上面不小心将 $PATH 覆盖掉了也不用担心,重新登录 shell 就好了。

至此,环境变量的定义如下:

环境变量是操作系统为了满足不同的应用场景,预先在系统内设置的一大批全局变量,这些变量往往具有特殊功能,且能够一直被 bash 以及 bash 的子进程访问。

注:环境变量具有全局属性的根本原因是环境变量会被子进程继承。

七、环境变量相关的命令

1、echo:显示某个环境变量的值
image-20230313140531288

2、export:设置一个新的环境变量

我们也使用export可以导出环境变量,使用env显示环境变量

image-20230313225544091

3、env:显示所有的环境变量
image-20230314001347560
部分环境变量说明:

环境变量名称表示内容
PATH命令的搜索路径
HOME用户的主工作目录
SHELL当前Shell
HOSTNAME主机名
TERM终端类型
HISTSIZE记录历史命令的条数
SSH_TTY当前终端文件
USER当前用户
MAIL邮箱
PWD当前所处路径
LANG编码格式
LOGNAME登录用户名

4、set:显示本地定义的shell变量和环境变量

不加export定义的就是本地变量,可以通过set命令查看本地变量,也可以查看环境变量:

image-20230315150238819

5、unset:清除环境变量
image-20230315150742969

八、环境变量的组织方式

在系统当中,环境变量的组织方式如下:
image-20230315144232284
每个程序都会收到一张环境变量表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串,最后一个字符指针为空。


九、命令行参数

前面获取环境变量是通过命令行的方式,下面我将通过代码程序来演示如何获取环境变量。

问:main函数可以带参数吗?最多可以带多少?

其实main函数的参数有3个,只是平时不经常用到,所以不太熟悉他们:

int main(int argc, char* argv[], char* envp[])
{return 0;
}

int argc:数组里的元素个数

char argv[ ]:指针数组*

我们先谈它的前两个参数,先来一段代码作为测试用例:

image-20230315161354386

运行结果如下:

image-20230315161314831

main函数的第二个参数是一个字符指针数组,此数组的下标0的位置存储的是你命令行的第一个位置(可执行程序),所以这里是第一行为:argv[0]:./myproc。其余的字符指针存储的是命令行对应的选项,所以会出现argv[1]:-a……,而main函数里的第一个参数存储的是数组里的元素个数。

image-20230315161854329

总结:我们给main函数传递的argc,char* argv[ ]是命令行参数,传递的内容是命令行中输入的程序名和选项,并且结尾以NULL束!!!

**问:**main函数传这些参数的意义是什么?

下面我们可以尝试编写一个简单的代码,该代码运行起来后会根据你所给选项给出不同的提示语句。

#include                                                                                            #include int main(int argc, char *argv[], char* envp[])
{if(argc > 1){if(strcmp(argv[1], "-a") == 0){printf("you used -a option...\n");}else if(strcmp(argv[1], "-b") == 0){printf("you used -b option...\n");}else{printf("you used unrecognizable option...\n");}}else{printf("you did not use any option...\n");}return 0;
}

image-20230315173807143

**综上:**同一个程序,通过传递不同的参数,让同一个程序有不同的执行逻辑,执行结果。Linux系统中,会根据不同的选项,让不同的命令,可以有不同的表现,这就是指令中各个选项的由来和起作用的方式!!这也就是命令行参数的意义,同样也就是main函数参数的意义。

下面来谈下main函数的第三个参数:

int main(int argc, char* argv[], char* envp[])
{return 0;
}

char*envp[] 就是环境变量。也是一个字符指针数组,前面的argv是指向的命令行参数字符串,而这里envp指向的是一个一个环境变量字符串,最后也是以NULL结尾。结构图如下:

image-20230315144232284

我们以如下代码来测试第三个参数:

int main(int argc, char* argv[], char* envp[])
{for (int i = 0; env[i]; i++){printf("envp[%d]: %s\n", i, envp[i]);}return 0;
}

image-20230315165133698

**总结:**一个进程是会被传入环境变量参数的。

**补充:**一个函数在声明和定义的时候都没有参数,那么我实际传参的时候可以传参。


十、通过代码获得环境变量

上面在学习main函数的三个参数的时候,我们得知通过main函数的第三个参数可以获得环境变量:

image-20230315165242902

image-20230315165133698

我们也可以通过第三方变量environ获取:

image-20230315165844504

image-20230315165731050


十一、通过系统调用获取环境变量

除了通过main函数的第三个参数和第三方变量environ来获取环境变量外,我们还可以通过系统调用getenv函数来获取环境变量。

getenv可以通过目标环境变量名进行查找,返回一个对应的字符指针,从而直接获得环境变量的内容:

image-20230315170612492

image-20230315170537316

问:我为什么要获得环境变量?

假设我们当前的用户USER为wei,但是我只允许自己使用,不允许其它人访问,就可以用获得环境变量来解决:

image-20230315171434505

此时用wei用户是可以正常访问的,但是zxy用户就不能了:

image-20230315171203293

综上,环境变量一定在某些地方有特殊用途,上面粗略的展示了其中一个方面。


十二、环境变量通常是具有全局属性的

先来回顾下bash进程:

image-20230315172616953

我们先前说过,子进程pid每次运行的结果是在不断变化的,因为其每次运行,进程都在重启,但是父进程是不变的,因为父进程就是bash,是系统创建的命令行解释器,

image-20230315172550885

如果我现在把bash杀掉,出现的结果是我输入任何命令都没有反应了,命令行直接挂掉。所以我们能够正常使用命令行,是因为这些命令本身就是被bash进程获得的。而这个bash进程是在我们登录系统时,系统自动帮你创建的。命令行中启动的进程,父进程全都是bash。

下面来理解环境变量具有全局属性:

看如下代码:(在原有的pid和ppid基础上添加了获取环境变量)

image-20230315173048245

通过运行结果得知:我们的进程刚开始并不存在环境变量,但是若我们自己导出一个环境变量,此时就获取到了环境变量

image-20230315173017596

总结:

环境变量是会被子进程继承下去的!!类比于从bash进程开始,往后创建一大批的子进程,若在bash进程的位置就创建了export环境变量,那么此环境变量就会从定义处bash位置开始被所有的子进程拿到。所以环境变量具有全局属性!!!

而本地变量之所以在本地有效,是因为本地变量是在bash内部定义的变量,不会被子进程继承下去!!!

补充:

image-20230315173142231

  • 这里local_val是一个本地变量,命令行中启动的所有程序都要创建子进程,echo也是一个命令、一个子进程, 你父bash内定义的local_val变量怎么能被子进程读到呢?不是说本地变量不会被子进程读到吗?后面为何能用echo打出hello呢?

Linux下大部分命令是通过子进程的方式执行的!但是,还有一部分命令,不通过子进程的方式执行,而是由bash自己执行(调用己的对应的函数来完成特定的功能),我们把这种命令叫做内建命令。


相关内容

热门资讯

【实验报告】实验一 图像的... 实验目的熟悉Matlab图像运算的基础——矩阵运算;熟悉图像矩阵的显示方法࿰...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
大模型落地比趋势更重要,NLP... 全球很多人都开始相信,以ChatGPT为代表的大模型,将带来一场NLP领...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
kuernetes 资源对象分... 文章目录1. pod 状态1.1 容器启动错误类型1.2 ImagePullBackOff 错误1....
STM32实战项目-数码管 程序实现功能: 1、上电后,数码管间隔50ms计数; 2、...
TM1638和TM1639差异... TM1638和TM1639差异说明 ✨本文不涉及具体的单片机代码驱动内容,值针对芯...
Qt+MySql开发笔记:Qt... 若该文为原创文章,转载请注明原文出处 本文章博客地址:https://h...
Java内存模型中的happe... 第29讲 | Java内存模型中的happen-before是什么? Java 语言...
《扬帆优配》算力概念股大爆发,... 3月22日,9股封单金额超亿元,工业富联、鸿博股份、鹏鼎控股分别为3.0...
CF1763D Valid B... CF1763D Valid Bitonic Permutations 题目大意 拱形排列࿰...
SQL语法 DDL、DML、D... 文章目录1 SQL通用语法2 SQL分类3 DDL 数据定义语言3.1 数据库操作3.2 表操作3....
文心一言 VS ChatGPT... 3月16号,百度正式发布了『文心一言』,这是国内公司第一次发布类Chat...
CentOS8提高篇5:磁盘分...        首先需要在虚拟机中模拟添加一块新的硬盘设备,然后进行分区、格式化、挂载等...
Linux防火墙——SNAT、... 目录 NAT 一、SNAT策略及作用 1、概述 SNAT应用环境 SNAT原理 SNAT转换前提条...
部署+使用集群的算力跑CPU密... 我先在开头做一个总结,表达我最终要做的事情和最终环境是如何的,然后我会一...
Uploadifive 批量文... Uploadifive 批量文件上传_uploadifive 多个上传按钮_asing1elife的...
C++入门语法基础 文章目录:1. 什么是C++2. 命名空间2.1 域的概念2.2 命名...
2023年全国DAMA-CDG... DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业发展里程碑及发展阶梯定义...
php实现助记词转TRX,ET... TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的...
【分割数据集操作集锦】毕设记录 1. 按要求将CSV文件转成json文件 有时候一些网络模型的源码会有data.json这样的文件里...
Postman接口测试之断言 如果你看文字部分还是不太理解的话,可以看看这个视频,详细介绍postma...
前端学习第三阶段-第4章 jQ... 4-1 jQuery介绍及常用API导读 01-jQuery入门导读 02-JavaScri...
4、linux初级——Linu... 目录 一、用CRT连接开发板 1、安装CRT调试工具 2、连接开发板 3、开机后ctrl+c...
Urban Radiance ... Urban Radiance Fields:城市辐射场 摘要:这项工作的目标是根据扫描...
天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...