【Linux】环境变量

发布于:2025-07-30 ⋅ 阅读:(19) ⋅ 点赞:(0)

环境变量

基本概念:

环境变量是操作系统或 shell 中定义的动态值,用于存储系统或应用程序运行时需要的配置信息,例如路径、用户信息、临时目录等。它们可以被系统中的进程(程序)读取和使用,是进程间传递信息的重要方式。

特点:

1.全局性
环境变量不仅在当前 shell 中有效,还会被子进程继承(即当前 shell 启动的其他程序或脚本也能访问这些变量)。这与 “本地变量”(仅在当前 shell 有效,不传递给子进程)形成鲜明对比。
2.键值对形式
环境变量以 变量名=值 的形式存在,例如 PATH=/usr/local/bin:/usr/bin 中,PATH 是变量名,/usr/local/bin:/usr/bin 是值。
3.区分大小写
在大多数 shell(如 Bash、Zsh)中,环境变量名通常为大写字母(约定俗成,便于区分系统变量和自定义变量),且大小写敏感(例如 PATH 和 path 是两个不同的变量)。
4.环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

作用:

1.简化程序配置:程序无需硬编码路径(如 HOME),直接读取环境变量即可适应不同用户或系统。
2.控制程序行为:例如通过 LANG 变量切换程序的语言显示,通过 PATH 控制程序的搜索范围。
3.进程间通信:父进程可通过环境变量向子进程传递参数(无需命令行参数)。

1.1补充内容

1.为什么函数返回值,会被外部拿到

1.基本类型 / 小型对象:主要通过寄存器传递
返回非引用类型和非指针类型时,返回值为临时对象,执行return语句时会放到cpu寄存器中,函数执行结束后,调用者(外部代码)从这些寄存器中读取返回值,完成传递。
2. 大型对象:通过栈传递
调用者在函数调用前,先在自己的栈帧上分配一块内存,用于存放返回值(这块内存的地址通过寄存器传递给被调用函数)。被调用函数执行return时,直接将返回值构造或拷贝到这块栈内存中(而非寄存器)。函数返回后,调用者直接从自己栈上的这块内存获取返回值。
3. 临时对象与编译器优化
对于非引用 / 非指针类型的返回值,理论上会产生临时对象,但现代编译器的返回值优化(RVO/NRVO) 会直接在调用者分配的内存中构造返回值,完全避免临时对象的创建(包括栈上的拷贝)。
这一过程与 “移动语义(move)” 不同:移动是对象资源的转移,而 RVO 是直接在目标地址构造,效率更高
因此,“返回值能被外部拿到” 的本质是编译器遵循统一的调用约定,通过寄存器或栈传递数据

2.系统如何得知我们进程执行到哪行代码了

通过程序计数器pc(一般性),eip(特殊性),来记录当前进程正在执行指令的下一行指令的地址

3.进程的切换

cpu中存在很多寄存器,为了提高运行效率,与进程相关的高频数据会放入寄存器中,cpu中寄存器保存的是进程的临时数据,被称为进程的上下文

进程在cpu上离开的时候要将自己的上下文数据保存好甚至带走,为了将来再次运行时更好的恢复,进程在被切换时一直会进行两个动作:
1.保存上下文
2.恢复上下文

如何保存数据:
将进程的硬件寄存器状态和内核管理状态完整存储到 PCB 中,确保再次调度时能精确恢复。这个过程由内核的中断处理程序和调度器协同完成,依赖 PCB 作为状态存储的载体,通常在PCB开辟一个结构体专门存储寄存器中相关信息.整个过程由软硬件协调完成缺一不可:
1.硬件负责 “快速保存 / 恢复核心寄存器”,是上下文切换的性能基础;
2…软件负责 “触发切换、管理完整上下文、决策调度”,是切换逻辑的主导者。
没有硬件支持,软件逐寄存器操作会导致切换效率极低;没有软件调度,硬件无法自主决定何时切换及切换到哪个进程。

常见环境变量

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

Windows下也有环境变量,本质是操作系统维护的一组key value值
在这里插入图片描述

1.2PATH : 指定命令的搜索路径

我们在Linux中所写的程序本质上也是指令,那么为什么系统中指令如ls pwd之类的直接输入不用加路径就可以运行,而自己写的可执行文件前需要加./表明当前路径下才能运行,就是因为PATH环境变量下存储了系统中指令的路径
在这里插入图片描述
查看环境变量方法:echo 查看环境变量前要加上$,否则会被当做字符串直接打印

1.若想直接运行自己的可执行文件,可将其路径加入到环境变量中
在这里插入图片描述
在这里插入图片描述
此时既可以./当前目录下指令运行,也可以像系统指令一样不带路径直接运行

2.若加入环境变量时,执行了PATH=…,这样是会覆盖路径
在这里插入图片描述
在这里插入图片描述
原本系统中的指令不能再直接运行,因为在环境变量中找不到它们所处的路径.那么如何恢复,PATH作为内存级别的环境变量,(临时修改,未写入配置文件情况下)只需退出xshell再重新登录即可恢复.
环境变量在系统的配置文件中就预先存好了,启动时会将其从配置文件中加载到内存

3.env指令可以查看当前进程以及从bash进程中所继承下来的所有环境变量

4.通过C/C++ 标准库中的函数getenv(“环境变量”)可以获取环境变量信息
在这里插入图片描述
在这里插入图片描述

1.3命令行参数

  • main函数的两个参数

main函数作为函数,那么一定可以被调用和传参,main函数并不是程序启动时第一个被调用的函数,而是在初始化工作完成后再被调用,命令行参数是为了在命令行模式下提供选项的支持int main(int argc, charargv[])
int argc:
表示程序启动时接收到的命令行参数的总个数(包含程序名本身).值至少为 1因为程序名本身会被算作第一个参数
char
argv[]:
是一个字符指针数组,每个元素指向一个以 null 结尾的字符串,存储具体的命令行参数内容。argv[0] 永远指向程序自身的名称或路径。argv[1] 到 argv[argc-1] 依次指向用户输入的其他参数。argv[argc] 被标准定义为 NULL(作为数组结束的标志)。
在这里插入图片描述
命令行参数以空格作为分隔符,bash将命令行参数打散做的是指令解析工作

#include<stdio.h>
  2 #include<string.h>
  3                                                                                                                                                                                                               
  4 int main(int argc,char*argv[])
  5 {
  6     if(argc!=2)
  7     {
  8         printf("Usage:%s -[a|b|c|d]\n",argv[0]);
  9     }
 10 
 11     if(strcmp(argv[1], "-a") == 0)
 12     {
 13         printf("功能1\n");
 14     }
 15     else if(strcmp(argv[1], "-b") == 0)
 16     {
 17         printf("功能2\n");
 18     }
 19     else if(strcmp(argv[1], "-c") == 0)
 20     {
 21         printf("功能3\n");
 22     }
 23     else if(strcmp(argv[1], "-d") == 0)
 24     {
 25         printf("功能4\n");
 26     }
 27     else
 28     {
 29         printf("default功能\n");
 30     }
 31     return 0;
 32 }

通过vim来测试输入指令时必须要带一个选项的情况

  • main函数可有三个参数,通过代码如何获取环境变量
    1.通过 main 函数的第三个参数 char *env[] 获取环境变量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中env是一个与argv相同结构的指针数组,存的是环境变量表,不再需要getenv来获取该进程指定的环境变量,可以直接通过env指针数组获取该进程的所有环境变量,与env指令查看所有环境变量执行结果相同

main 函数的 env 参数是 C 标准(C89 及以上)明确支持的特性,符合标准。
优点:跨平台兼容性更好,无需依赖系统特定的全局变量。
缺点:需要修改 main 函数的参数列表(添加 char *env[])。

2.通过 extern char **environ; 声明全局变量 environ,直接访问环境变量。

environ 是 Unix/Linux 系统中一个非标准但广泛实现的全局变量,指向环境变量的字符串数组。没有包含在任何头文件中,所以在使用时 要用extern声明。
优点:无需修改 main 函数的参数,直接使用 environ 变量。
缺点:依赖系统实现(非 C 标准),在某些环境中可能不可用(如 Windows 或严格遵循 POSIX 的系统)。
在这里插入图片描述

适用场景建议

1.优先使用 main 的 env 参数:
符合 C 标准,跨平台兼容性更好,代码更规范。适合需要严格遵循标准的项目。
2.仅在必要时使用 environ:
如果无法修改 main 函数的参数(如已有代码结构不允许),或依赖系统特定行为时,可使用 environ。但需注意兼容性问题。

在C和C++代码中一共有两张核心向量表
1.命令行参数表charargv[]
2.环境变量表char
env[]
于此可以加深理解:
进程在运行时不要简单认为就是简单把程序加载到内存,而是自己的程序变为进程时要调用main函数将两张核心向量表传进来

我们所运行的进程都是子进程,bash本身在启动时,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程给我的环境变量,这也证明了环境变量具有全局属性

写main函数时如何判断带几个参数?先写的代码再进行编译,这时后编译器就会进行参数的检查看是否用到参数相关

1.4本地变量与内建命令

  • 本地变量

本地变量是指仅在当前 shell 会话或脚本中有效,且不会被子进程继承的变量。它是 shell 变量的一种,与 “环境变量” 相对应,主要用于在当前上下文临时存储数据。
特点:
1.作用范围有限
仅在定义它的当前 shell 中有效,无法被当前 shell 启动的子进程(如另一个脚本、命令、新的 shell 会话等)访问。
2.定义方式简单
直接通过 变量名=值 的格式定义,无需特殊关键字。
3.默认不被子进程继承
这是与环境变量最核心的区别。环境变量可以通过 export 命令标记,从而被子进程继承;而本地变量即使不被 export,也仅在当前 shell 生效。

本地变量是系统层上的概念,定义方式如下,在env环境变量表中无法找到
在这里插入图片描述
只能通过echo来打印该本地变量
在这里插入图片描述

  • 内建命令

命令分为两种
1.常规命令:通过创建子进程完成的
2.内建命令:bush不创建子进程,而是由自己亲自执行,类似于bash调用了自己写的,或者系统提供的函数

特点:
1.无独立进程:执行时不创建新进程,直接在当前 shell 进程中运行。
2.操作 shell 内部状态:可以修改 shell 变量、环境变量、执行逻辑等(如 cd 命令必须是内建的,否则无法改变当前 shell 的工作目录)。
3.执行效率高:无需加载外部程序,响应速度更快。

场景分析:

在这里插入图片描述
通过概念的学习,知道本地变量只在bash内部有效,不会被继承,echo打印语句是bash的子进程,为什么还能打印出myee这个被创建的本地变量呢?
答案就是echo是内建命令,并没有创建子进程去执行该命令而是bash亲自执行

常见的内建命令(以 Bash 为例):

  • 基础操作类

cd:切换当前工作目录(必须是内建命令,否则无法影响当前 shell)。
示例:cd /home/user
pwd:显示当前工作目录的绝对路径。
示例:pwd
echo:输出字符串或变量值。
示例:echo “Hello $USER”
printf:格式化输出(类似 C 语言的 printf)。
示例:printf “Name: %s\nAge: %d” “Alice” 30

  • 变量与环境类

export:将本地变量标记为环境变量,使其能被子进程继承。
示例:export PATH=$PATH:/new/dir
unset:删除变量或函数。
示例:unset my_var(删除变量 my_var)
set:显示或设置 shell 变量、控制 shell 选项(前文已详细说明)。
env:显示当前环境变量(非内建也可,但 Bash 中通常作为内建实现)。

  • 流程控制类

if/then/else/fi:条件判断语句
for/while/until:循环语句。
case/esac:多分支条件判断。
break/continue:中断循环或跳过当前循环迭代。

  • 函数与脚本类

function/():定义 shell 函数。
return:从函数中返回(类似 exit,但仅退出函数)。
source/.:在当前 shell 中执行脚本文件(而非创建子进程)。

  • 其他常用内建命令

alias:定义命令别名(如 alias ll=‘ls -l’)。
unalias:删除别名。
history:显示命令历史记录。
read:从标准输入读取用户输入并赋值给变量。
示例:read -p "输入姓名: " name
exit:退出当前 shell 进程。
type:判断一个命令是否为内建命令(或外部程序)。

  • 如何区分内建命令与外部命令?

使用 type 命令名 可以判断:
内建命令:输出 xxx is a shell builtin。
外部命令:输出其可执行文件路径(如 xxx is /usr/bin/xxx)。

1.5与环境变量相关的指令

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

想定义环境变量在前面加一个export导出即可
在这里插入图片描述
在这里插入图片描述
会出现在bash的上下文中,这就决定并证明了所有子进程都会继承父进程的环境变量(命令行下所创建的子进程),证明环境变量具有全局属性

  • unset: 专门用于删除变量、函数或别名的内建命令。

1.unset 默认删除本地变量,若变量同时是环境变量(被 export 标记),unset 会同时从当前 shell 和环境中删除它(子进程中若已继承该变量则不受影响)。
2.不能删除只读变量:如果变量被 readonly 标记为只读,unset 无法删除,会报错
3.批量删除(谨慎使用):不建议直接 unset 不加参数(会删除所有自定义变量,保留系统默认变量),可能导致 shell 环境异常。
在这里插入图片描述
删除后环境变量表中无法找到

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

直接在终端输入 set 并回车,会列出当前 shell 中所有已定义的变量(包括本地变量、环境变量以及函数),输出内容通常按字母顺序排列,格式为 变量名=值。
本地变量:仅 set 显示、而 env 不显示的变量(仅当前 shell 有效,不被子进程继承)。
注意:
1.如果想单独查看环境变量,可以用 env 或 printenv 命令
2.若输出内容过多,可通过管道符 | 配合 grep 过滤特定变量

其他常用功能
1.设置变量:
通过 set 定义或修改变量set name=“Alice” (不推荐,更常用的是直接用变量名=值的方式)
2.控制shell选项:
set 可以开启 / 关闭 shell 的某些功能(通过选项参数),例如:
set -u:当使用未定义的变量时,shell 会报错(默认忽略)。
set -e:如果命令执行失败(返回非 0 状态),立即退出 shell 脚本。
set -x:在执行命令前,先输出命令本身(用于脚本调试)。
关闭选项用 - 改为 +,例如 set +x 关闭调试输出。
3.处理位置参数
在 shell 脚本中,set 可以重新设置位置参数($1、$2 等):
在这里插入图片描述

  • echo: 显示某个环境变量值

echo $环境变量名

  • env指令: 显示所有环境变量

网站公告

今日签到

点亮在社区的每一天
去签到