在 Linux 系统中,环境变量就像神经网络中的“神经元”,连接着系统的各个组件,确保指令、数据和状态信息能够在用户、进程和操作系统之间高效传递。它们是系统运行的隐形规则,决定了许多关键行为和运行逻辑。
1.基本概念
1.1 什么是环境变量?
1.2 命令行参数
C语言的main函数也有参数吗?答案是有的。
通过下面的例子,我们发现main函数的参数与命令行参数有关
argc表示传递给程序的命令行参数的数量(以空格作为分隔符),包括程序名本身。
argv是一个指向字符串数组的指针,每个字符串代表一个命令行参数。argv[0]
是程序的名称,后面的元素是用户输入的参数。argv用来实现选项功能。
下面这段代码的作用是实现一个简单的命令行参数解析器,根据输入的选项(-a
、-b
、-c
)执行对应的功能,并在参数无效时提供正确的使用提示。
上面的结果反映了main的命令行参数,是实现程序不同子功能的方法,而这正是linux指令选项的原理。
2. 一个例子,一个变量
2.1 自定义程序命令与系统命令
通过上面的学习,我们对指令选项作用原理有了浅薄的认识,那么我们再来思考一下为什么执行code时需要使用./code,而使用系统命令时(例如 ls )可直接使用?
(1) 要执行一个命令,必须先找到它。linux系统中“ . ”表示当前目录,./code则表示在当前目录下执行名称为./code的文件。
(2)系统中存在环境变量,来帮助系统寻找二进制文件(怎么找?bash通过PATH(环境变量)来找)
ls本质上是一个usr/bin/目录下的二进制文件(指令的本质就是在系统里提前预装的二进制程序)。
为什么我们不需要写路径,系统就能直接找到ls命令呢?这是因为系统会直接到usr/nbin/目录下去寻找。系统为什么会到usr/bin目录下去寻找呢?因为系统中存在环境变量PATH, 该环境变量告诉系统搜索指令的默认搜索路径。
而如果我们将自己写的二进制文件,也拷贝到usr/biin/目录下,就可以不带路径直接执行了
查看一个环境变量:echo $环境变量
以冒号作为分隔符,依次在上面各个绝对路径下查找是否有该命令
例如使用ls,首先在/usr/local/bin目录下查找是否有该命令,没有则继续在/usr/bin目录下查找,找到了则调用该命令,
正因为有PATH,所以我们执行ls不用带路径,不用写成/usr/bin/ls。
我们可以手动将一个路径添加到PATH,这样系统就会自动到该路径目录下查找
上面的方法是直接赋值,会将当前的路径覆盖到PATH中。直接退出xshell重新登陆即可恢复。
给PATH添加路径:PATH=$PATH:路径
同样,退出xshell再重新连接 ,手动添加的路径就会消失
2.2 从存储角度理解环境变量
当我们登录时,系统会创建一个bash进程,bash从系统中读取所有的环境变量信息,在bash内部形成一张表->环境变量表(一个指针数组)
当我们输入一个命令时,例如"ls -a -b",这个命令先被bash拿到,然后构建命令行参数表(argv),这样bash就可拿着命令的名字去环境变量表中找到PATH,在PATH路径下寻找命令是否存在,存在则创建子进程执行。
2.3 环境变量从哪里来
环境变量最开始从系统中的相关配置文件来的
这个文件在每次打开新的交互式非登录 shell 时执行。它通常用于配置 shell 的行为,如别名、Shell 函数、提示符等。
使用场景:当你在一个已打开的终端中打开一个新的标签或窗口时,.bashrc 会被执行。这是设置日常命令的地方。
下面的这个文件在用户登录时执行,通常用于设置环境变量和启动需要在整个会话中使用的程序。
使用场景:当你通过 SSH 登录或者在控制台中打开一个新的终端界面时,.bash_profile会被执行。它用来配置影响整个用户会话的设置。
我们只要将路径按下图添加到.bash_profile中,该路径就不会因退出而消失
总结:
bash内部会有两张表,一个是环境变量表,一个是命令行参数表,不管是命令行参数还是环境变量,都是这同样结构的表中对应的字符串
3. 更多环境变量
(1)HOME
表示当前用户的家目录,通常是/home/username。
cd ~之所以能切换路径到家目录就是因为当用户在终端输入cd ~并按下回车时,bash获得命令ls和参数~,bash会在参数处理之前将 ~ 被扩展为 $HOME
环境变量的值,从而执行命令。
cd HOME的值 //进入家目录
(2) SHELL
表示当前用户的默认 Shell 程序路径,常见的有:
/bin/bash
(Bash Shell)
/bin/zsh
(Zsh Shell)
/bin/sh
(POSIX Shell)
(3)USER
表示当前登录用户的用户名。
(4)LOGNNAME
表示当前登录会话的用户名。
在大多数情况下,USER
和 LOGNAME
会有相同的值,但它们的来源可能略有不同。USER
更多用于 Shell 环境,而 LOGNAME
更常见于系统级别的设置和处理。
(5)HSITSIZE
可以保存的命令历史记录条数。
(6)HOSTNAME
表示当前计算机的主机名。
(7)OLDPWD
表示用户上一次所在的工作目录路径
cd -能够切换依赖于此
进入根目录
回到上一个目录
4. 获得环境变量的方法
4.1 操作
4.1.1. 查看
(1)env
env(environment):查看所有环境变量
(2)echo $环境变量
查看一个环境变量:echo $环境变量
(3)set
在 Bash 中,set
命令不仅显示当前 Shell 中所有变量(包括环境变量),还显示局部变量等。
4.1.2. 导入、取消
(1)export用于将一个 Shell 变量(局部变量)导出为环境变量,使其能够在当前 Shell 会话及其子进程中被访问和使用。
//基本语法
export VARIABLE_NAME=value
(2)unset用于删除一个变量或者函数,使其不再存在。对于环境变量,unset会将变量从当前 Shell 会话和其子进程中移除。
4.2 在代码中使用
4.2.1 env
环境变量以字符串的形式被打印出来,之前有提到不管是命令行参数还是环境变量,都是这同样结构的表中对应的字符串,现在是不是对这句话有了更深刻的理解?
命令行参数表和环境变量表是父进程传递给main的,子进程、子子进程都可以继承export的新的环境变量。
所以说,环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
为什么环境变量要可以被子进程继承?因为子进程继承环境变量,就可以结合环境变量来做个性化操作比如编写一个只能让自己执行的程序。
4.2.2 getenv
用于获取环境变量的值。它可以通过指定环境变量的名称来返回该变量的值。如果该环境变量不存在,则返回NULL。
一个只能自己使用的程序:
4.2.3 setenv
用于设置或修改环境变量的值。它允许程序在运行时更改环境变量,从而影响当前程序及其子进程的行为。
函数原型:
int setenv(const char *name, const char *value, int overwrite);
参数:
name:要设置的环境变量的名称(一个 C 字符串)。
value:该环境变量的新值(一个 C 字符串)。
overwrite:一个整数,指定是否覆盖已存在的环境变量。如果overwrite为非零值,且name指定的环境变量已经存在,那么该变量的值将被新值覆盖。如果overwrite为 0,且该环境变量已经存在,则不会修改它。
(1)设置一个新的环境变量
这段代码会设置 MY_VAR
环境变量的值为 "HelloWorld"
。由于 overwrite
参数为 1,如果该环境变量已经存在,它的值将被覆盖。
#include <stdio.h>
#include <stdlib.h>
int main() {
// 设置一个新的环境变量
if (setenv("MY_VAR", "HelloWorld", 1) == 0) {
printf("MY_VAR 已设置为: %s\n", getenv("MY_VAR"));
} else {
perror("setenv 出错");
}
return 0;
}
(2)不覆盖已存在的环境变量
在这个例子中,如果 MY_VAR
已经设置,它将保持原有值 "HelloWorld"
,而不是被 "AnotherValue"
覆盖,因为 overwrite
参数为 0。
#include <stdio.h>
#include <stdlib.h>
int main() {
// 如果 MY_VAR 已存在,覆盖它
setenv("MY_VAR", "NewValue", 1);
// 不覆盖已经存在的 MY_VAR
if (setenv("MY_VAR", "AnotherValue", 0) == 0) {
printf("MY_VAR 的值为: %s\n", getenv("MY_VAR"));
} else {
perror("setenv 出错");
}
return 0;
}
4.2.4 environ
environ 是一个全局变量,在 C 语言中用于访问当前进程的环境变量。它是一个字符指针数组,指向每个环境变量的字符串表示。
查看所有环境变量
environ与getenv的区别
environ是一个全局变量,它是一个字符指针数组,包含了当前进程的所有环境变量。通过遍历 environ可以访问所有的环境变量。
getenv是一个函数,它用于查询单个环境变量的值。相比之下,getenv更方便用于查询单一环境变量,而environ更适合于需要遍历所有环境变量的场景。
5. 环境变量的组成部分
环境变量的组成部分包括本地变量、全局变量、内建命令、系统变量、用户定义变量和导出变量,这些元素共同影响程序的执行和系统的配置。
5.1 本地变量
本地变量指的是在当前 shell 会话或进程中定义的变量,它们的作用范围通常局限于当前进程。关键点在于它们 不会自动被子进程继承,只在bash内部被使用,但如果使用 export
命令将它们导出为环境变量,它们就会被继承到子进程。
shell也支持本地变量,本地变量通常通过export命令或类似机制在 Shell 中设置。
作用范围:本地变量只对当前 Shell 会话有效。一旦会话结束,变量会被销毁。它们不影响系统的全局环境。如果用户想让其在下次会话中仍然可用,需要将其写入到配置文件(例如 .bashrc
或 .profile
)。
set可以显示环境变量和本地变量
本地变量有许多特殊的用途
例如ps2='> ' 续行
5.2 内建命令
内建命令是指由 Shell 本身提供的命令,用于直接与环境变量交互或配置环境。这些命令不需要创建子进程,让bash亲自执行调用函数或系统调用完成。
上面介绍的export、unset、env、set都是内建命令。
在 Linux 中,环境变量是操作系统与程序之间沟通的重要桥梁,它们不仅帮助配置系统的行为,还为用户和程序提供了一种灵活的方式来管理和传递配置信息。从本地变量到内建命令,每一个细节都能在我们与系统交互时发挥重要作用。通过了解和掌握环境变量的使用,能够让我们更高效地配置和定制系统环境,优化开发和运维过程。无论是在调试程序时查看环境配置,还是在日常工作中调整路径设置,环境变量都是我们与系统之间不可或缺的“幕后英雄”。