Linux系统篇(三):Linux 命令行参数 & 环境变量:程序和系统沟通的底层逻辑
一句话总结:环境变量就是操作系统里的「全局配置参数」,程序和命令可以直接读取使用,用来知道 “系统在哪里、怎么运行、默认配置是什么”。你可以把它理解成:系统给所有程序共享的 “小纸条”,上面写着路径、配置、用户名、临时目录等信息。

很多刚接触 Linux C 开发的同学,都会遇到两个 “拦路虎”:
为什么 main 函数要写 int argc, char *argv[ ]?echo $PATH 里的路径到底是怎么让命令跑起来的?
其实,命令行参数和环境变量,就是程序和操作系统沟通的两大核心通道:一个负责接收用户单次运行时的指令,
一个承载着系统全局的运行配置。
这篇文章就带你从 bash 解析命令行的底层过程讲起,把 argv 数组、environ 全局变量、环境变量的继承机制这些知识点一次性讲透,让你彻底搞懂程序和系统的 “对话逻辑”。

1.什么是环境变量
一句话总结:环境变量就是操作系统里的「全局配置参数」,程序和命令可以直接读取使用,用来知道 “系统在哪里、怎么运行、默认配置是什么”。
你可以把它理解成:
系统给所有程序共享的 “小纸条”,上面写着路径、配置、用户名、临时目录等信息。
1. 最直观的例子:PATH 环境变量
ls
gcc
gdb
cgdb
python
为什么系统知道去哪里找这些命令?
因为它们的路径被写进了 PATH 环境变量 里。
系统会按 PATH 里记录的路径挨个找,找到就运行。
2.环境变量长什么样?
1.格式:变量名 = 值
PATH=/usr/bin:/bin:/usr/local/bin
HOME=/home/user
LANG=en_US.UTF-8
PWD=/home/user/project
3. 环境变量从哪里来?
当你登录 Linux 系统,打开终端时,bash 会自动加载一系列配置文件,环境变量就是在这里被初始化的:
/etc/profile:系统级配置,对所有用户生效
~/.bashrc:用户级配置,只对当前用户生效
~/.bash_profile:用户登录时执行的配置文件
你可以用ls -la查看家目录下的这些隐藏文件,它们定义了你的 bash 环境,包括别名、路径、环境变量等。
4.常见的环境变量
| 环境变量 | 作用 |
| PATH | 命令搜索路径(最重要) |
| HOME | 当前用户主目录 |
| PWD | 当前所在目录 |
| LANG | 系统语言 / 编码 |
| SHELL | 当前使用的 shell |
| LD_LIBRARY_PATH | 动态库搜索路径(C/C++ 常用) |
5.Linux 下查看 / 设置环境变量的命令
1.查看所有环境变量
env

2.查看某个环境变量
echo $PATH
echo $HOME
echo $LD_LIBRARY_PATH

echo $PATH 里的 $ 是什么意思?
PATH 是一个环境变量的名字。
当你写 $PATH 时,Shell 会把它替换成这个变量里存的实际内容(也就是一长串目录路径)。
所以 echo $PATH 执行的效果,就是把 PATH 变量里存的所有路径打印出来。
如果不加 $,Shell会把PATH当成普通字符串打印

3.临时设置环境变量(关闭终端失效)
export MY_VAR="hello"
export PATH=$PATH:/new/path

4.
6.对环境变量的浅层了解

幕后的运行逻辑是这样的:
以前敲 text.exe 报错:
当你只输入 text.exe 时,系统不知道这个文件在哪。Linux 出于安全考虑,默认不会在当前目录下找程序。所以你必须加 ./(代表当前目录),告诉系统:“就在当前目录下运行这个程序!”
现在直接敲 text.exe 成功:
当你输入任何一个命令时,Linux 都会去一个叫 $PATH 的环境变量里记录的几个固定文件夹中,挨个去搜有没有同名的文件。
7.main函数的三个参数
// 标准三参数 main 函数
int main(int argc, char *argv[], char *envp[])
三个参数分别是:
argc:命令行参数的个数(整数)
argv:命令行参数的字符串数组
envp:系统环境变量字符串数组(第三个参数,最常用的扩展形式)
#include <stdio.h>
// 三参数 main
int main(int argc, char *argv[], char *envp[])
{
// 1. 打印参数个数
printf("参数个数 argc = %d\n", argc);
// 2. 打印所有命令行参数
printf("\n命令行参数 argv:\n");
for (int i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
// 3. 打印前5个环境变量(envp 以 NULL 结尾)
printf("\n环境变量 envp (前5个):\n");
for (int i = 0; envp[i] && i < 5; i++) {
printf("envp[%d] = %s\n", i, envp[i]);
}
return 0;
}
1.argc

2.argv[ ]

#include <stdio.h>
#include <string.h> // 必须引入这个头文件来使用 strcmp
int main(int argc, char *argv[], char *envp[])
{
// 先确保用户至少输入了一个额外的命令行参数
if (argc > 1)
{
// argv[0] 是程序名自己("./text.exe")
// argv[1] 才是你输入的第一个真正参数(比如 a 或 b)
if (strcmp(argv[1], "a") == 0) // strcmp 返回 0 代表字符串完全相等
{
printf("a\n");
}
else if (strcmp(argv[1], "b") == 0)
{
printf("b\n");
}
}
else
{
printf("请在运行程序时传入参数 a 或 b!\n");
}
return 0;
}
2.argv[ ]
#include <stdio.h>
// 三参数 main,envp 指向环境变量数组
int main(int argc, char *argv[], char *envp[])
{
printf("=== 前5个环境变量 ===\n");
for (int i = 0; i < 5 && envp[i] != NULL; i++) {
printf("envp[%d]: %s\n", i, envp[i]);
}
return 0;
}
8.程序中如何访问环境变量
1. 通过environ全局变量
environ是一个全局的字符指针数组,和argv类似,它指向所有环境变量字符串,最后以NULL结尾。

#include <stdio.h>
extern char **environ;
int main()
{
for(int i = 0; environ[i] != NULL; i++)
{
printf("%s\n", environ[i]);
}
return 0;
}

2. 通过main函数的第三个参数
7.2演示过
3.通过getenv函数(推荐)
如果只想获取某个特定环境变量,用getenv最方便:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("当前用户:%s\n", getenv("USER"));
printf("家目录:%s\n", getenv("HOME"));
printf("当前路径:%s\n", getenv("PWD"));
return 0;
}
getenv("变量名")会返回该变量的值的字符串指针,如果变量不存在则返回NULL。

9.环境变量的特性与操作
1. 环境变量的作用域
环境变量有一个关键特性:被子进程继承,但不会反过来影响父进程。
你在 bash 中设置的环境变量,会被 bash 启动的所有子进程(比如你的 C 程序)继承。
子进程修改环境变量,只会影响自己和它的子进程,父进程(bash)完全不受影响。
比如你在程序里修改了HOME,退出程序后,bash 里的$HOME还是原来的值。
2. 常用操作命令
echo $变量名:查看环境变量的值
export 变量名=值:设置环境变量,让它被子进程继承
unset 变量名:删除环境变量
env:查看所有环境变量
export MY_VAR="hello world"
echo $MY_VAR # 输出 hello world
./your_program # 程序中用getenv("MY_VAR")就能获取到值
unset MY_VAR # 删除变量
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
// main 三参数:argc, argv, envp(环境变量)
int main(int argc, char *argv[], char *envp[])
{
pid_t pid = fork(); // 创建子进程
if (pid == -1) {
perror("fork失败");
return 1;
}
if (pid == 0) {
// ====================
// 子进程
// ====================
printf("===== 子进程 PID = %d =====\n", getpid());
for (int i = 0; i < 5 && envp[i] != NULL; i++) {
printf("子进程 envp[%d] = %s\n", i, envp[i]);
}
} else {
// ====================
// 父进程
// ====================
printf("===== 父进程 PID = %d =====\n", getpid());
for (int i = 0; i < 5 && envp[i] != NULL; i++) {
printf("父进程 envp[%d] = %s\n", i, envp[i]);
}
// 等待子进程结束(避免输出混乱)
wait(NULL);
}
return 0;
}
10.本地变量

1.特点:
只在当前函数里能用
存在栈(stack) 上
函数结束就销毁
2. fork () 之后,本地变量会发生什么?
父进程有的本地变量,子进程会全部复制一份!
但:
✔ 复制完之后,父子的变量是完全独立的!
✔ 你改子进程的,父进程不受影响
✔ 你改父进程的,子进程也不受影响
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
// 父进程里的本地变量
int a = 10;
pid_t pid = fork(); // 创建子进程
if (pid == 0) {
// ==================
// 子进程
// ==================
a = 20; // 子进程改自己的 a
printf("子进程:a = %d\n", a);
}
else {
// ==================
// 父进程
// ==================
wait(NULL); // 等子进程跑完
printf("父进程:a = %d\n", a);
}
return 0;
}

终极结论
fork 之后:
子进程复制父进程的所有本地变量
但父子变量是独立的
一方修改,不会影响另一方
再用一句话总结
1.本地变量 = 各自的副本
2.fork = 完整复制一份
3.改自己的 = 不影响别人
11.常见误区与补充
修改环境变量的误区:
很多人以为在程序里修改环境变量会影响 bash,其实不会。因为 bash 启动程序时,会把环境变量复制一份给子进程,子进程的修改只在自己的地址空间里生效,不会写回父进程。
PATH的查找顺序:
bash 会按PATH里目录的顺序依次查找,先找到哪个目录下的可执行文件,就运行哪个。所以尽量不要把当前目录.加到PATH里,会有安全风险。
内建命令与外部命令:
有些命令(比如cd、export)是 bash 的内建命令,不是外部程序。它们直接在 bash 进程内部执行,所以可以修改 bash 的环境变量;而ls、cat这类外部命令,运行时是 bash 的子进程,无法修改 bash 的环境。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐




所有评论(0)