013 环境变量

环境变量

1. 什么是环境变量?

环境变量(Environment Variables)是操作系统中用于指定系统运行环境参数的一组动态键值对。每个环境变量由一个 名称(键) 和一个 组成,用于存储应用程序或系统需要访问的配置信息。例如:

  • 名称PATH
  • /usr/bin:/usr/local/bin

环境变量的作用类似于操作系统的“配置开关”,可以影响程序的运行行为、路径搜索、资源访问等。

1. 环境变量的分类

根据作用范围和修改权限,环境变量可分为两类:

1. 用户环境变量(User Variables)
  • 作用范围:仅对当前用户生效。
  • 用途:存储用户个性化配置(如用户专属的软件路径)。
2. 系统环境变量(System Variables)
  • 作用范围:对所有用户和系统进程生效。
  • 用途:存储全局配置(如系统工具路径、公共依赖库路径)。
3. 临时环境变量
  • 作用:仅在当前终端会话或子进程中有效。

2. 和环境变量相关的命令

  • echo:显示某个环境变量值
  • export:设置一个新的环境变量
  • env:显示所有环境变量
  • unset: 清除环境变量
  • set:显示本地定义的 shell 变量和环境变量

2. 常见环境变量及用途

变量名 作用 示例值
PATH 执行文件的查找的路径,目录与目录中间用 : 分隔。注意:文件查找是按 PATH 变量内的目录来查询的,所以,目录顺序很重要 /usr/bin:/usr/local/bin
HOME 当前用户的家目录(根目录) /home/user
USER 当前用户名 user
SHELL 告知我们目前这个环境使用的 SHELL 是哪个程序?默认 Shell 程序路径 /bin/bash(Linux 默认使用)
LANG 系统语言和字符编码 en_US.UTF-8
PWD 当前工作目录 /home/user/projects

还有 自定义变量: 你可以定义自己的变量来影响程序行为。示例:MY_VAR=123

[!CAUTION]

自定义变量和本地变量在概念上有些相似,但它们并不完全相同。

  1. 自定义变量:手动创建的变量,默认是 本地变量
  2. 本地变量:默认不使用 export,只在当前 Shell 生效,子进程无法访问。
  3. 环境变量:通过 export 声明,子进程也能访问。

判断标准: 是否用 export 导出,决定了变量是本地的还是环境的。


自定义变量:

  • 定义方式: 直接赋值,或者使用 export 命令声明。
  • 作用范围: 根据是否使用 export,它可以是 本地变量 或者 环境变量
  • 示例:
1
2
MY_VAR="Hello World"  # 定义自定义变量
echo $MY_VAR # 输出:Hello World

本地变量(Local Variable):

  • 定义方式: 在当前 Shell 会话中赋值,不使用 export
  • 作用范围: 仅在 当前 Shell 会话 内有效,不会被子进程继承。
  • 示例:
1
2
3
LOCAL_VAR="I am local"
bash # 打开新的子 Shell
echo $LOCAL_VAR # 无输出,子 Shell 无法访问父 Shell 的本地变量

环境变量(Environment Variable):

  • 定义方式: 使用 export 命令导出。
  • 作用范围:当前 Shell 以及所有 子进程 中都可用。
  • 示例:
1
2
3
export ENV_VAR="I am environment"
bash # 打开新的子 Shell
echo $ENV_VAR # 输出:I am environment

3. 查看环境变量

  1. 查看单个变量
1
2
echo $NAME 		//NAME为待查看的环境变量名称,例如:echo $PATH
printenv NAME //NAME为待查看的环境变量名称,例如:printenv USER

image-20250319184829137

image-20250319185701254

  1. 查看所有环境变量
1
printenv  		# 或 env,输出一模一样

image-20250319185045556


4. 设置环境变量

1. 为什么 ls 命令可以直接执行,而我们自己的可执行程序需要带上路径(如 ./)来执行的问题?

原因:PATH 它是一个环境变量,指定了一个目录列表,系统会在这些目录中搜索用户输入的命令。当你在终端中输入一个命令(例如 ls),系统会按照 PATH 中列出的顺序查找该命令,并执行找到的第一个匹配项。像 ls 这样的命令之所以可以不带路径直接执行,是因为它们所在的目录(通常是 /bin/usr/bin 等)被包含在了系统的 PATH 环境变量中。因此,当你输入 ls 时,系统能够在指定的目录中找到并执行这个命令。

2. 我们自己生成的可执行程序为什么不能直接执行?

当我们创建了自己的可执行程序并尝试在终端运行时,默认情况下当前工作目录(即 . 代表的目录)通常不会包含在 PATH 环境变量中。这说明:当我们在终端输入自己程序的名字时,系统不会自动在当前目录下查找该程序。因此,我们需要使用 ./ 前缀来明确指出要执行的是当前目录下的程序。

3. 如何让自定义的可执行程序无需带路径就能直接运行?

要让自定义的可执行程序无需带路径就能直接运行,你需要将它所在的目录添加到 环境变量 PATH 中。这样,当你在命令行中输入程序名时,系统会在 PATH 指定的目录中查找该可执行程序。以下是详细步骤:

1. 临时生效(仅当前终端有效)

1
2
# 假设程序放在 /home/user/myprogram/ 目录下
export PATH="$PATH:/home/user/myprogram"

测试验证

1
2
echo $PATH                 # 查看 PATH 是否包含目录
myprogram # 直接运行你的程序(无需路径)

取消临时设置:临时添加的路径在会话结束后就会丢失。 如果想手动取消,使用 unset 命令:

1
unset PATH  			  # 或者将 PATH 恢复为原始值

2. 永久生效(对所有终端和子进程生效)

如果希望即使重启终端或计算机后仍然有效,可以将 export 命令添加到用户的启动文件中(如 .bashrc.bash_profile.zshrc 等),这样每次打开终端时就会自动设置。

根据自己使用的 Shell 选择配置文件:

  • Bash~/.bashrc~/.bash_profile
  • Zsh~/.zshrc

[!NOTE]

简单解释一下:

  • Bash 是最常见的默认 shell,适合日常使用和脚本编写。

  • Zsh 是更强大、功能丰富的 shell,特别适合喜欢定制和使用插件的用户。

  • Xshell 作为终端模拟器,可以连接到 Linux 服务器,使用的 shell 是由服务器设置的,可以是 Bash 或 Zsh。

可以通过以下命令来查看当前使用的是哪个 shell:

1
echo $SHELL
  • 如果返回的结果是 /bin/bash,那说明你使用的是 Bash
  • 如果返回的结果是 /bin/zsh,那说明你使用的是 Zsh

这里以我的 Bash 为例:

1
vim ~/.bashrc

在文件末尾添加这一行:

1
export PATH=$PATH:/home/user/myprogram			# 或者export PATH="$PATH:/home/user/myprograms"

保存并退出编辑器,使配置生效:

1
source ~/.bashrc  # 或 source ~/.bash_profile,重新加载配置文件

测试:

1
2
echo $PATH  # 查看 PATH 变量,确认是否添加成功
myprogram # 直接执行程序,无需路径

3. 取消永久设置:

如果不再需要这个路径,可以编辑 .bashrc.bash_profile,删除那一行,然后重新执行 source 命令:

1
2
vim ~/.bashrc  		 # 删除 export PATH 行
source ~/.bashrc # 使配置生效

5. 注意事项

  1. 安全性

    • 不要将当前目录 . 添加到 PATH(如 export PATH=".:$PATH"),这会允许当前目录下的任意程序被执行,存在安全风险。
  2. 路径优先级

    • PATH 中目录的顺序决定查找优先级。例如:

      1
      2
      export PATH="/my_dir:$PATH"  # 优先搜索 /my_dir
      export PATH="$PATH:/my_dir" # 最后搜索 /my_dir
  3. 多用户系统

    • 若需所有用户生效,可修改系统级配置文件(如 /etc/profile/etc/environment),但需 root 权限。
  4. 误删了 PATH 变量怎么办?

    • 恢复默认 PATH:
    1
    export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

6. 理解 HOME 环境变量

在 Linux 系统中,每个用户都有一个专属的工作目录,称为 主目录(Home Directory)。这个目录是用户登录系统后的默认位置,用户可以在其中存储个人文件、配置文件等。

  • HOME 是一个环境变量,存储了当前用户的主目录路径。
  • 每当登录到系统时,系统会分配一个 主目录,通常位于 /home/用户名,例如,假设我的用户名是 hcc,那么我的主目录就是 /home/hcc

在终端中,使用命令 echo $HOME,系统会返回当前登录用户的主目录路径:

image-20250322204611987

1. 主目录的作用

  1. 默认工作目录
    • 当登录到系统时,通常会自动进入主目录。这个目录是我们个人的空间,通常可以放置配置文件、文档、程序文件等。
  2. 保存用户的配置文件
    • 在主目录下,用户的配置文件(如 .bashrc.zshrc 等)存放在那里。这样,无论我们从哪个位置打开终端,都会读取这些文件的配置。
  3. 用户的私有空间
    • 每个用户在系统中都有自己的主目录,确保用户数据和配置是隔离的,不会互相干扰。

2. HOME~ 的关系

~HOME 变量的简写,表示当前用户的主目录。可以在命令行中使用 ~ 来快速访问主目录。例如:

1
cd ~  # 等同于 cd $HOME,切换到当前用户的主目录

这样,无论处在哪个目录下,~ 都会自动被替换为我们的主目录路径。

每个用户的工作目录(主目录)都是独立且唯一的。 即使是同一台机器上的多个用户,它们的主目录路径也不同,这样可以保证用户数据的隔离和安全。

image-20250322205018865


7. 环境变量的组织方式

image-20250322205313857


8. 如何通过代码获取环境变量

1. 通过命令行的第三个参数获取环境变量

要在 C 语言中获取和操作环境变量,我们可以通过以下几种方式:

  1. 通过命令行第三个参数(env[])获取环境变量:这是通过命令行启动程序时传递给 main() 函数的第三个参数。
  2. 通过第三方变量 environ 获取环境变量environ 是一个外部变量,包含了环境变量的列表。
  3. 通过系统调用获取或设置环境变量:可以使用 getenv() 来获取环境变量的值,使用 putenv() 来设置环境变量。

main() 函数的第三个参数 char *env[] 是一个指向环境变量的字符串数组,数组中的每个元素都是一个格式为 KEY=VALUE 的字符串。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
printf("获取命令行参数:\n");
for (int i = 0; i < argc; i++)
{
printf("参数[%d]: %s\n", i, argv[i]);
}

printf("\n获取环境变量:\n");
for (int i = 0; env[i] != NULL; i++)
{
printf("环境变量[%d]: %s\n", i, env[i]);
}

return 0;
}

输出:

image-20250323133118466

2. 通过 environ 获取环境变量

environ 是一个外部全局变量,包含当前环境变量的数组,它是 char **environ 类型。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
extern char **environ;
int main()
{
printf("通过 environ 获取环境变量:\n");
for (int i = 0; environ[i] != NULL; i++)
{
printf("环境变量[%d]: %s\n", i, environ[i]);
}

return 0;
}

输出:

image-20250323133624112

3. 使用 getenv()putenv() 系统调用获取和设置环境变量

常用 getenvputenv 函数来访问特定的环境变量。

  • getenv():获取指定环境变量的值。
  • putenv():设置一个新的环境变量或修改已有环境变量的值。
示例:获取和设置环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <stdlib.h>
extern int putenv(char *string); // 添加putenv的显式声明

int main()
{
// 获取环境变量
char *home = getenv("HOME");
if (home)
{
printf("HOME 环境变量的值: %s\n", home);
}
else
{
printf("HOME 环境变量未设置。\n");
}

// 设置环境变量
putenv("MYVAR=MyCustomValue");
char *myvar = getenv("MYVAR");
if (myvar)
{
printf("MYVAR 环境变量的值: %s\n", myvar);
}

// 修改环境变量
putenv("MYVAR=NewValue");
myvar = getenv("MYVAR");
if (myvar)
{
printf("修改后的 MYVAR 环境变量的值: %s\n", myvar);
}

return 0;
}

解释和输出:

  1. getenv():获取环境变量的值,如果变量存在,返回该变量的值;如果不存在,返回 NULL
  2. putenv():设置环境变量,参数是一个格式为 KEY=VALUE 的字符串。putenv 会修改当前进程的环境变量,不需要重新调用 setenv()unsetenv() 来更新。

image-20250323134534197


9. 环境变量通常是具有全局属性的

  1. 获取环境变量: 在程序中,通过 getenv("MYENV") 获取环境变量 MYENV 的值。如果该变量存在,程序会打印出它的值。

    示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>
    #include <stdlib.h>

    int main()
    {
    char *env = getenv("MYENV"); // 获取环境变量
    if (env)
    {
    printf("%s\n", env); // 如果环境变量存在,则打印
    }
    return 0;
    }
  2. 没有结果: 程序首次运行时,显示没有结果,表示 MYENV 环境变量并未被设置。

  3. 设置环境变量: 通过执行 export MYENV="hello world" 命令,设置环境变量 MYENV,并再次运行程序,结果成功打印了 hello world,表示环境变量是可以在当前进程中继承并使用的。

image-20250323135915861

注意: 如果我们直接在命令行中设置 MYENV="helloworld" 而不使用 export,在我们的 C 程序中是无法获取到这个环境变量的。

解释:

  • export 是用来 将环境变量传递给子进程 的命令。如果在命令行中仅设置了 MYENV="helloworld",这个环境变量只在当前 shell 会话中有效,但不会影响到子进程或其他程序。
  • 使用 export 后,环境变量会被子进程继承并传递,这就是为什么在使用 export 设置了 MYENV 后,程序能够成功读取到该变量的原因。