Linux进程(四)概念:命令行参数和环境变量篇
在 Linux 编程、Shell 开发里,命令行参数 和 环境变量 是进程和外部传递信息的两种核心方式。命令行参数是程序启动时一次性传给程序的参数;环境变量附着在进程上,是一组全局的键值对,子进程默认继承父进程的环境变量。现在我们一起从概念、命令、内核组织、系统调用、代码示例梳理该部分知识点。
目录
方式 2:全局变量 environ(不需要改 main 形参)
一、 概念
1. 命令行参数
程序启动时,在命令行后跟的参数,传递给 main 函数。 C 语言标准 main 写法:
int main(int argc, char* argv[]);
argc(argument count):参数个数,程序本身也算一个参数
argv(argument vector):字符串指针数组,argv[0] 是程序名,argv[1] 是第一个参数,argv[argc] = NULL 作为结束标记
示例:./test aaa bbb
argc = 3
argv[0] = "./test"
argv[1] = "aaa"
argv[2] = "bbb"
命令行参数只在本次启动生效,不会传给其他进程,也不是全局的。
2. 环境变量
环境变量是进程级别的全局键值对,格式:KEY=VALUE。 作用:给进程提供全局配置、运行上下文。 典型特点:
父进程创建子进程时,子进程默认继承父进程全部环境变量;
环境变量修改默认只在当前进程内生效,不影响父进程;
是进程的运行上下文,Shell、编译工具、程序都依赖它。
重点:环境变量是进程内全局,不是操作系统全局。不同进程可以有不一样的环境变量,修改子进程环境变量不会改父进程。
二、环境变量
1.常见的环境变量
表格
| 变量名 | 含义 |
|---|---|
PATH | 命令搜索路径,Shell 找可执行文件时,按 PATH 里的目录依次查找 |
HOME | 当前用户家目录 |
USER | 当前登录用户名 |
PWD | 当前工作目录(和 getcwd 对应,之前代码里用到) |
OLDPWD | 上一次的工作目录,cd - 依赖它 |
SHELL | 当前使用的 Shell 程序,一般是 /bin/bash |
LD_LIBRARY_PATH | 动态链接库搜索路径 |
LANG | 语言编码、字符集 |
2.查看环境变量的方法
env:列出当前进程所有环境变量

printenv:和 env 几乎一样,打印环境变量

echo $VAR:查看单个环境变量
echo $PATH
echo $PWD


set:不仅打印环境变量,还会打印 Shell 本地变量(本地变量≠环境变量,不会被子进程继承)
区分:环境变量可以被子进程继承;Shell 本地变量只在当前 Shell 有效,子进程看不到。
3.shell命令
export VAR=xxx:把本地变量导出为环境变量,子进程可以继承
或

unset VAR:删除环境变量

export不带参数:查看所有被导出的环境变量

4. 环境变量在进程中的组织方式

Linux 中,每个进程有自己独立的环境表,本质是一个char* 指针数组,数组最后一个元素是 NULL 标记结束。 C 语言 main 函数完整三参数版本:
int main(int argc, char* argv[], char* env[]);
env 就是环境表:
env[0] = "PATH=/usr/bin:/bin";
env[1] = "HOME=/home/xxx";
env[2] = "PWD=/root";
...
env[n] = NULL;
在进程的地址空间中:
命令行参数、环境变量字符串,都放在进程栈区上方的环境区;
内核创建进程时,会把父进程的环境表拷贝一份给子进程;
环境表指针 environ 是一个全局外部变量,所有 C 程序都可以使用。
全局变量声明:
extern char** environ;这个environ和main的第三个参数env指向同一块环境表。
5. 程序中获取环境变量的两种方式
方式 1:main 函数第三个参数 env
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{
for(int i = 0; env[i]; i++)
{
printf("%s\n", env[i]);
}
return 0;
}
结果如下:

方式 2:全局变量 environ(不需要改 main 形参)
#include <stdio.h>
extern char** environ;
int main()
{
for(int i = 0; environ[i]; i++)
{
printf("%s\n", environ[i]);
}
return 0;
}
结果如下:

6. 库函数 / 系统调用:获取、设置环境变量
getenv/setenv/putenv是 C 标准库函数,底层封装了对进程环境表的操作,不是直接系统调用;真正的系统调用是exec系列、fork等。
6.1 getenv:获取指定环境变量
头文件 <stdlib.h>
char *getenv(const char *name);
传入变量名,返回对应值的指针;找不到返回 NULL。
不修改环境表。
6.2 setenv:设置环境变量
int setenv(const char *name, const char *value, int overwrite);
overwrite=1:如果变量已经存在,覆盖旧值;
overwrite=0:已存在则不修改;
函数内部会自己分配内存存放字符串,没有悬空指针风险。
6.3 putenv:设置环境变量
int putenv(char *string);
参数格式必须是 KEY=VALUE;
不会拷贝字符串!直接保存传入指针的地址
如果传入栈上局部数组,函数退出后栈回收,环境变量变成野指针,程序崩溃。 就是你之前 GetPwd 代码里的那个坑!
6.4 unsetenv:删除环境变量
int unsetenv(const char *name);
6.5 clearenv:清空当前进程所有环境变量
int clearenv(void);
7. 特性:环境变量是进程内全局属性
环境变量在当前进程内部是全局可见的,进程内所有函数都可以调用 getenv/setenv 访问;但是默认只在当前进程和它的子进程生效,对父进程、其他无关进程没有任何影响。
fork 创建子进程:子进程拷贝一份父进程环境表;父子后续修改互相独立;
exec 加载新程序:默认继承当前进程环境表;
想修改父进程的环境变量:普通子进程做不到,Shell 里只有内置命令(cd、export)才会直接修改 Shell 本身环境,外部程序无法修改父 Shell 环境。
三、总结
Linux 下命令行参数与环境变量,二者是进程接收外部信息的两大途径:命令行参数是程序启动时一次性传入的参数;环境变量是附着在进程上的KEY=VALUE键值对,子进程默认继承父进程环境变量。
- 命令行参数:依靠
argc(参数个数)、argv(参数字符串数组)传递,argv[0]代表程序名,仅本次程序运行有效,不具备继承性。- 环境变量基础:属于进程内全局,不是操作系统全局,修改子进程环境不会影响父进程;列举了
PATH、HOME、PWD等常用环境变量。- Shell 操作命令:使用
env / printenv / echo $变量名 / set查看;export导出环境变量、unset删除变量,export、unset、cd属于 Shell 内置命令,不能搭配 sudo 执行。- 底层组织形式:环境表是
char*指针数组,以NULL收尾;可以通过 main 第三个参数env或者全局外部变量environ遍历环境表。- C 语言库函数(头文件
<stdlib.h>)
getenv:读取指定环境变量;setenv:安全设置变量,内部自动管理内存;putenv:直接保存传入字符串指针,传入栈数组会造成野指针风险;unsetenv删除单个变量、clearenv清空全部环境变量。- 核心特性:fork 出的子进程会拷贝父进程环境表,父子后续修改互不干扰;exec 加载程序默认继承环境;外部可执行程序无法修改父 Shell 的环境,只有 Shell 内置命令可以修改 Shell 自身环境。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)