【Linux系统】环境变量




在这里插入图片描述



一、通俗例子解释环境变量概念与作用


想象你在厨房做饭,需要找到各种调料和工具。这些调料和工具就相当于计算机中的“资源”,而环境变量就像厨房里的一本规则书,里面列出了厨房里所有调料和工具的位置。

  1. 具有全局性(所有人都能用):就像这份规则书对家里所有成员都是可用的一样,全局环境变量在整个系统内都是可见和可用的。类似地,什么用户在使用计算机,都可以使用同一份环境变量来找到所需的信息。
  2. 记录查找的固定路径:规则书中记录了盐、糖、油等常用调料的固定存放位置,全局环境变量也定义了操作系统查找常用工具和资源的标准位置。类似地,系统环境变量 PATH 指定了操作系统查找可执行文件的标准路径,用户可以通过程序名快速启动该程序。
  3. 易于维护:如果规则书中的某项信息发生了变化,只需要更新规则书,家里所有人都会知道新的位置。同样,更改全局环境变量后,整个系统内的所有程序都会使用更新后的信息。
  4. 初始设置(配置通用):当家庭成员第一次使用厨房时,这份规则书可以帮他快速知道必要的操作知识。类似地,当一个新的用户登录系统,或者一个新的进程启动时,全局环境变量提供了必要的初始配置。

通过这个例子,我们可以看出全局环境变量就像是一个通用的规则集,它在整个操作系统中为所有用户和进程提供了统一的配置信息。


二、Linux中常见的环境变量


  1. PATH
    • 描述:指定系统搜索可执行文件的目录路径。
    • 示例:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    • 作用:当用户在命令行输入一个命令时,系统会在PATH变量指定的目录中查找相应的可执行文件。
  2. HOME
    • 描述:用户的主目录路径。
    • 示例:/home/username
    • 作用:许多程序会根据HOME变量确定用户的主目录位置。
  3. LANG
    • 描述:语言环境设置。
    • 示例:en_US.UTF-8
    • 作用:控制程序使用的语言和字符集。
  4. SHELL
    • 描述:用户的默认Shell。
    • 示例:/bin/bash
    • 作用:指示用户的默认Shell类型。
  5. USERLOGNAME
    • 描述:当前登录用户的用户名。
    • 示例:username
    • 作用:许多程序会根据此变量来确定当前用户的用户名。
    • 这两个环境变量其实有本质区别:【Linux】Linux 环境变量中 LOGNAME 和 USER 有什么本质区别
  6. PWD
    • 描述:当前工作目录。
    • 示例:/home/username
    • 作用:表示当前用户所在的工作目录。
  7. OLDPWD
    • 描述:上一次的工作目录。
    • 命令 cd - :可以跳转到上一次的工作路径,这条命令底层就是通过获取环境变量 OLDPWD 实现的


我们下面通过认识一个很常见的环境变量 PATH 来进入我们的环境变量的深入学习 :

三、谈谈环境变量 PATH


我们在使用 Linux 系统时,其实已经使用过该环境变量,例如使用系统命令如 lstouch……

这些命令本质上都是在系统目录 /usr/bin/ 下的可执行文件,而你需要给系统提供某个可执行文件的全路径,系统会根据路径在对应目录下找到并执行该可执行文件。

在Linux系统中,用户可以仅输入命令名称而不是完整路径来执行该命令的可执行程序,这是因为系统会在环境变量 PATH 定义的目录中查找可执行文件。当你输入一个命令时,shell 会检查这个变量中列出的每一个目录,看看其中是否包含一个与你输入的名字匹配的可执行文件。

环境变量PATH 包含了多个目录路径,这些路径之间通常用冒号(:)分隔。当一个命令被执行时,Linux系统会依次搜索这些目录中的文件。如果在任何一个目录中找到了匹配的可执行文件,那么这个命令就会被执行。

常见的目录包括/bin/usr/bin/usr/local/bin等,这些目录包含了操作系统提供的许多基本命令。

例如:我查看我的 Linux 系统中的环境变量 PATH 如下

在这里插入图片描述


比如你输入ls命令,系统会在 $PATH 指定的所有目录下查找名为ls的文件。

如果希望执行不在$PATH中的程序或者想要执行某个目录下的特定程序,可以使用绝对路径或相对路径来指定程序的完整路径,例如/usr/local/myapp/mycommand



1、执行自己的程序而不带路径的两种方式:

  • 1、将你的程序拷贝到当前环境变量 PATH 中存储的任一路径目录底下
  • 2、直接将自己程序的全路径,添加到环境变量 PATH

(1)命令 pwd

命令 pwd :查看当前你的可执行程序所处路径

在这里插入图片描述



(2)命令 echo $PATH

命令 echo $PATH :查看当前环境变量 PATH 内容,并手动复制该值(你修改新的 PATH 需要把别人之前的值一起保留)

在这里插入图片描述



(3)手动添加自己路径

手动将你的程序路径添加该环境变量 PATH 字符串后面:以冒号作为分隔符

原PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
我要添加的路径 /home/mine/linux-learning
两者合并 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/mine/linux-learning


(4)命令 export PATH=变量值

命令 export PATH=变量值 :将新的环境变量 PATH 添加到环境变量表中,更新环境变量 PATH

最后可以命令 echo $PATH检查一下是否修改成功

在这里插入图片描述



(5)检验结果

声明:我在当前路径下创建一个可执行文件 test1 ,用于打印 hello world

  • 第一次命令 test1:只需要该可执行程序名,系统会在环境变量 PATH 的目录中找到并执行我们的 可执行文件 test1

在这里插入图片描述

  • 第二次命令 ./test1:这次则提供了该可执行文件的路径,系统直接通过该路径就能找到该可执行程序的位置并执行


2、修改环境变量会永久保存吗?


环境变量,开始都是在系统的配置文件中的!

shell 进程的环境变量的由来:我们登陆系统 => 启动一个shell进程 => 读取用户和系统相关的环境变量的配置文件 => 形成自己的环境变量表 => 会继承给子进程

因为我们每次启动一个shell进程都会读取系统的配置文件来进行初始配置,因此我们刚刚自行修改了环境变量 PATH 只是对此次启动的 shell进程的环境变量做修改,而并不会永久保留下来,退出该 shell 进程,所做的修改就会消失,下次启动新的 shell 进程,则又是读取系统文件来配置,由此也可以得出一个方法:若想要永久修改系统的环境变量,可以手动添加或修改系统的相关配置文件。



四、环境变量的组织方式


每个程序都会收到一张环境变量表,环境变量表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境变量字符串

用于将本进程的所有环境变量集中存储在一个字符串数组,最后以 NULL 结尾。


在这里插入图片描述




五、查看环境变量(五种方法)


通过命令查看

(1)命令 env

**命令 env:**查看当前进程的环境变量表,会打印出当前shell环境下的所有环境变量及其值,以 variable=value 的形式展示。




(2)命令 echo $env_name

命令 echo $env_name:查看名为 env_name 的环境变量

例如我指定查看环境变量 USER 的值(上面这张图的最后一行那个)

在这里插入图片描述



通过代码查看


(3)命令行第三个参数

命令行第三个参数main 函数的第三个参数环境变量表 envp

main 函数中,存在三个函数参数:int main(int argc, char *argv[], char *envp[]);,参数 char *envp[] 就是用于接收父进程传递的环境变量表。

(若想要具体了解一下 main 的各个参数具体从何而来,可以看看此篇博客:【Linux】main函数的参数列表从何而来?-CSDN博客)


代码演示

因为环境变量表 envp 最后一个元素是 NULL 因此可以直接通过这个作为遍历环境变量表的结束判断

#include<stdio.h>

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

如下图,将该程序 main 函数接收到的环境变量表打印出来

在这里插入图片描述



(4)通过第三方变量environ获取

C语言标准库中定义的全局变量 environ 是一个字符串数组指针,指向的是当前进程的(虚拟)内存空间中全局数据区存储的那个环境变量表,就是子进程继承于父进程的那个环境变量表。(这里暂时不讨论为什么要加一个“虚拟”的修饰)

environ 没有包含在任何头文件中,所以在使用时 要用 extern 声明。


代码演示
#include <stdio.h>

extern char **environ;

int main()
{
    for(int i = 0; environ[i]; i++){
        printf("%s\n", environ[i]);
    }
    return 0;
}

如下图,将该程序将全局变量 environ 指向的环境变量表打印出来

在这里插入图片描述




通过系统调用获取或设置


(5)函数 getenv(char* env_name)

getenv 函数在C语言中用于检索当前进程的环境变量。它是一个标准库函数,用于获取指定环境变量的值,使用需要的头文件为 <stdlib.h>

getenv函数通常在程序中用来访问环境变量,而不需要显式地处理环境变量表。


代码演示

打印环境变量 PATH

#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("%s\n", getenv("PATH"));
    return 0;
}

运行结果如下

在这里插入图片描述


(6)函数 putenv(char *string) :更改或设置环境变量

putenv函数在C语言中用于修改环境变量的值。它允许您设置或修改当前进程的环境变量,并且这些修改会影响到后续创建的子进程。putenv函数通常用于在程序中更改环境变量的值。

1、如果环境变量已存在putenv会修改现有环境变量的值。

2、如果环境变量不存在putenv会创建一个新的环境变量,并将其添加到环境变量表中。


代码演示

注意:该函数是修改当前进程的环境变量表,不会对父进程造成影响,因此运行一个下面代码的可执行文件,本质修改的是这个运行的子进程的环境变量表,因此需要前后将环境变量表打印出来看看

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

extern char **environ;

int main()
{
    // 修改前
    for(int i = 0; environ[i]; i++){
        printf("environ[%d] : %s\n", i, environ[i]);
    }
    
    
    putenv("Myenv=hello_Linux!!!!");
    
    
    
    // 分割线
    printf("\n——————————————————————\n\n");
    
    // 修改后
    for(int i = 0; environ[i]; i++){
        printf("environ[%d] : %s\n", i, environ[i]);
    }
    
    return 0;
}

运行结果如下

为了观感,我把部分没必要的部分删掉了

在这里插入图片描述



六、与环境变量相关的命令


这两个本文前面讲解过了,这里不赘诉:

echo: 显示某个环境变量值

env: 显示所有环境变量


(1)export: 设置一个新的环境变量

该命令可以向当前进程的环境变量表中导入一个环境变量

1、如果变量不存在:当环境变量表中不存在你导入的变量,则将该新环境变量添加进来

2、如果变量已经存在:当环境变量表中已经存在你导入的变量,则会对表中的旧值更新成你新导入的

3、如果导入的变量没有赋值,同时变量不存在:当你要导入的环境变量没有赋值,则默认值为空,也会导入到表中

4、如果导入的变量没有赋值,同时变量已经存在:即没有指定新的值,那么原表中变量的值将保持不变(不会被空值影响)


运行结果如下:

在这里插入图片描述



(2)unset: 清除环境变量

使用格式:指定环境变量名即可

unset MY_VARIABLE
echo $MY_VARIABLE  # 输出: (不会输出任何东西,因为变量已被删除)

注意,unset命令会完全移除环境变量

运行结果如下:移除上一张图中添加的环境变量(本来是在环境变量 LESSCLOSE 前面的)

在这里插入图片描述



(3)set: 显示本地定义的 shell 变量和环境变量

命令 set 不区分环境变量和其他类型的变量(如本地变量),一律打印

运行结果如下:


在这里插入图片描述




七、本地变量

本小段内容用于补充:

概念

在Linux系统中,Shell环境中有两种类型的变量:本地变量(local variables)和环境变量(environment variables)。本地变量只在当前Shell会话中有效,不会传递给任何子进程,而环境变量不仅在当前Shell会话中有效,还会传递给子进程。


本地变量:相当于程序内的局部变量,只能被局部域使用(只在当前Shell会话中有效)
环境变量:相当于程序内的全局变量,可以被全局任何地方使用(全局有效,可以传给子进程一起用)

由于本地变量的局部性,因此在该 bash 进程关闭后,本地变量也就没了,重新启动一个新 bash 进程不会看到之前创建的本地变量。

如果你想要添加 “永久性的本地变量”,就需要修改添加到系统的相关配置文件中,因为一个 bash 进程启动前会读取系统的配置文件,配置一些初始变量及其他数据。



创建本地变量:

输入 variable=value 就能创建成功,通过命令 echo $变量名 就能查看目标本地变量的值
在这里插入图片描述


将本地变量变成环境变量


//定义一个本地变量
a=10
   
// 导成环境变量
export a

验证是否导入:env打印环境变量出来看
在这里插入图片描述



八、添加变量的本质


添加环境变量的本质:其实就是在进程中 malloc 一块空间,保存该变量

过程如下:

1、分配内存:为新的环境变量字符串分配内存。

2、更新环境变量表:在环境变量表中找到合适的位置插入新的环境变量字符串。

3、更新环境变量表的终止符:确保环境变量表以NULL终止


在系统中添加本地变量也是一个道理,都是先分配内存,然后保存该本地变量。



九、环境变量的传递过程(重要)


继承环境变量

  • 当父进程通过fork()创建子进程时,子进程会继承父进程的环境变量列表。这意味着子进程在创建时已经有了与父进程相同的环境变量列表。
  • 这一过程是通过fork()函数自动完成的,不需要额外的操作。

执行新程序

子进程创建完成后,通常父进程会调用exec系列的函数替换这个创建出来的子进程,用于执行新的程序。

  • 如果父进程没有修改自己的环境变量表,父进程通过exec函数传递给子进程这张未修改过的 “旧表”。(本质还是该子进程创建时继承自父进程的环境变量列表)
  • 如果父进程修改了自己的环境变量表,父进程通过exec函数传递给子进程这张修改过的 “新表”

如果父进程执行 fork + exec 的过程创建子进程,该子进程实际上会接收两次环境变量,第一次子进程接受的环境变量表是 fork 函数默认拷贝,第二次是 exec 函数直接传递的,不过最后子进程的环境变量表是 exec 函数传递的那一份(也就是最新的一份)。

澄清:子进程在通过 fork 函数创建时已经有了与父进程相同的环境变量列表,相当于子进程的本体就有。因此只是看上去子进程接收了两次。

环境变量可以被子进程继承,这里证明了环境变量的一个大作用:进程具有独立性,进程间信息互不干扰,但是可以通过环境变量完成进程间信息的传递!!!



十、为什么环境变量具有全局性?

点击跳转本篇博客,可得到更加详细的讲解:【Linux】为什么环境变量具有全局性?写时拷贝优化?-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MCU SCT文件学习

硬件&#xff1a;GD32F427, 外设&#xff1a;FreeRtos,ADC,DMA 现象&#xff1a;注释掉一些线程&#xff0c;发现ADC采样的线程采样不到数据了。 开始猜测是线程重入&#xff0c;破坏了地址&#xff0c;后来思考一下发现不对&#xff0c;因为注释掉线程&#xff0c;ADCDMA采…

【Vulnhub靶场】DC-4

DC-4靶场下载地址https://www.five86.com/downloads/DC-4.zip 本机IP&#xff1a;192.168.118.128 靶机IP&#xff1a;192.168.118.0/24 信息收集 扫描主机存活&#xff0c;扫描端口&#xff0c;扫描服务 第一步扫描出主机ip为192.168.118.141 nmap -sP 192.168.118.0/24 nm…

高级 SQL 技巧全面教程:提升你的数据库操作能力

高级 SQL 技巧全面教程&#xff1a;提升你的数据库操作能力 引言 在数据驱动的时代&#xff0c;SQL&#xff08;结构化查询语言&#xff09;是与数据库交互的核心工具。虽然基础 SQL 语法足以满足日常需求&#xff0c;但掌握一些高级技巧能够显著提高你的工作效率和数据处理能…

Node.js初学者指南:搭建HTTP服务器、获取请求信息及响应、变量声明与NPM包管理

精神畅快&#xff0c;心气平和&#xff1b;饮食有节&#xff0c;寒暖当心&#xff1b;起居以时&#xff0c;劳逸均匀 文章目录 node.js使用http搭建服务器的问题获取请求相关的信息响应相关的信息var、let、const对比npm使用全局安装包 node.js 概念 node.js是一个基于Chrome …

RTE 2024 隐藏攻略

大家好&#xff01;想必今年 RTE 大会议程大家都了解得差不多了&#xff0c;这将是一场实时互动和多模态 AI builder 的年度大聚会。 大会开始前&#xff0c;我们邀请了参与大会策划的 RTE 开发者社区和超音速计划的成员们&#xff0c;分享了不同活动的亮点和隐藏攻略。 请收…

使用Poste搭建内网邮件服务器

使用Poste搭建内网邮件服务器 Poste.io 也是一个流行的邮件服务器方案&#xff0c;它可以通过 Docker 容器轻松部署&#xff0c;非常适合搭建内部邮件服务器。 本文档将向您展示如何开始使用 Poste.io 邮件服务器。在 5 分钟内&#xff0c;您将拥有一个可发送和接收邮件的邮件…

WSL2 Ubuntu22.04编译安装LLVM

前提 这两天因为工作需要&#xff0c;要编译一个Debug版本的llvm。这里对编译安装过程进行一个简单的记录&#xff0c;同时也记录下这个过程中遇到的几个问题。 下载源码并编译 有关llvm编译安装的官方文档在这里。 从git仓库clone llvm的源码。 git clone https://github.c…

SD-WAN企业组网的应用场景

SD-WAN&#xff08;软件定义广域网&#xff09;能够实现企业不同站点之间的高效互联&#xff0c;确保分支机构、总部、数据中心以及云平台等站点的顺畅通信。本文将探讨从企业的WAN业务需求出发&#xff0c;可以将SD-WAN的组网场景分为哪几类。 SD-WAN的典型组网场景 企业站点之…

Docker中如何控制服务启动顺序实现探讨

文章目录 一、Docker概述二、Docker三剑客1. Compose2. Machine3. Swarm 三、简要需求1. 样例工程2. 代码模块3. 调用方向4. 期望启动顺序 四、思路分析1.各走各路1.&#xff09;docker-compose -f指定不同配置文件2.&#xff09;docker-compose up -d service-name指定服务名3…

基于SpringBoot的高校体测管理系统设计与实现(源码+定制+开发)高校体测记录系统设计、高校体测信息管理平台、智能体测管理系统开发、高校体测记录系统设计

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

如何将markdown文件转换为pdf

最近笔者在用vscode写markdown&#xff0c;但是提交时往往需要交pdf。所以就涉及到如何将markdown转化为pdf格式。 首先&#xff0c;需要在vscode上安装插件 markdown Preview Enhanced 之后在vscode的右上角即可看到下述图标&#xff0c;点击&#xff0c;vscode右半面就会显示…

Spring Boot驱动的植物健康监测革命

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理植物健康系统的相关信息成为必然。开发合适…

VulkanTutorial(1·简述,vs环境搭建)

介绍&#xff1a; 与OpenGL&#xff0c;WebGL和Direct3D等API&#xff08;(Application Programming Interface, 应用程序编程接口)&#xff09;相比&#xff0c;valkan更偏向于底层&#xff0c;有更多的GPU控制接口&#xff0c;因此它有更好的性能和更小的驱动开销&#xff0…

检索增强型生成模型RichRAG:为多面查询提供丰富回应

人工智能咨询培训老师叶梓 转载标明出处 大模型在处理静态知识更新和信息准确性方面仍面临挑战。为了解决这些问题&#xff0c;检索增强型生成&#xff08;RAG&#xff09;模型应运而生&#xff0c;它们通过检索文档来辅助语言模型生成更可靠的回答。但现有的RAG研究大多集中在…

springboot079信息化在线教学平台的设计与实现(论文+源码)_kaic

信息化在线教学平台的设计与实现 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了信息化在线教学平台的开发全过程。通过分析信息化在线教学平台管理的不足&#xff0c;创建了一个计算机管理信息化在线教学平台…

【人工智能】——matplotlib教程

文章目录 1.matplotlib简介2.基本绘图功能2.1给图形添加辅助功能2.2在一个坐标系中绘制多个图像2.3多个坐标系显示图像 3.常见图像绘制 1.matplotlib简介 matplotlib 是一个用于创建二维图表和数据可视化的 Python 库&#xff0c;它提供了一种类似于 MATLAB 的绘图接口。matplo…

Mybatis-07.基础操作-环境准备

一.需求说明 二.准备工作

网关三问:为什么微服务需要网关?什么是微服务网关?网关怎么选型?

文章整体介绍 本文旨在解答关于微服务网关的三个核心问题&#xff1a; 1&#xff09;为什么需要网关&#xff1f;也即在何种场景下应采用微服务网关以优化系统架构&#xff1b; 2&#xff09;什么是微服务网关&#xff1f;主要讲构成微服务网关的关键能力&#xff0c;包括但…

再传上市消息,奇瑞汽车追赶智能电动的“风”

近日&#xff0c;彭博社引述消息指出&#xff0c;奇瑞控股集团已选择中金公司、广发证券、华泰国际负责安排旗下汽车子公司奇瑞汽车潜在的IPO事宜。奇瑞汽车最早或于明年在香港上市&#xff0c;期望IPO估值超1,000亿元人民币。知情人士表示&#xff0c;审议仍在进行中&#xff…

Compose 修改默认点击效果

Compose 默认点击效果修改 一、Compose的默认点击效果二、实现自己的点击效果 一、Compose的默认点击效果 使用Modifier.clickables可以使Text有点击效果 Text(text "我是Text", modifier Modifier.clickable {})源码分析&#xff0c;点击效果clickable方法中的in…