子进程通过fork+exec自动继承父进程已导出的环境变量;fork复制environ数组,execve默认传递该数组,未export的变量不进入环境块,故子进程不可见。

子进程天然继承父进程的环境变量,不需要额外操作——这是 Linux 进程创建机制决定的,关键在于理解“继承”发生的时机和前提。
继承自动发生,前提是正确调用 fork + exec
当父进程调用 fork() 创建子进程时,子进程会完整复制父进程的内存空间,包括整个环境变量数组(environ)。但此时子进程还运行着和父进程相同的程序。真正启动新程序(比如 ls、python)靠的是 exec 系列系统调用(如 execve)。只要调用 execve 时不显式传入新的环境变量数组,内核就会默认把当前进程已有的环境变量原样传递给新程序。
- shell 中执行命令(如
ls -l)就是典型例子:bash fork 出子进程,再 execve 启动ls,PATH、HOME等全部自动可用 - 在 C 程序中,用
execl("/bin/ls", "ls", "-l", (char*)NULL)就继承;而用execle("/bin/ls", "ls", "-l", (char*)NULL, envp)则可指定全新环境
确保父进程的环境变量已正确设置并导出
继承的是“当前进程实际持有的环境变量”,不是文件里写好的、没加载的配置。如果父进程(比如你的 shell)没把变量 export 出去,它只是本地变量,不会进入环境块,也就无法被子进程看到。
- 错误示范:
MYVAR=hello→ 子进程echo $MYVAR输出为空 - 正确做法:
MYVAR=hello; export MYVAR或简写为export MYVAR=hello - 验证是否生效:
printenv MYVAR能输出值,才说明已进入环境块
避免常见干扰:终端、登录 Shell 和配置文件加载顺序
看似“没继承”,常常是因为你误以为某个变量已在父进程中存在,其实它根本没加载进来。
- 非登录 shell(如脚本中启动的 bash)默认不读
.bash_profile,只读.bashrc;确保变量写在被实际加载的文件里 - 图形界面终端启动的 shell 可能是非登录 shell,
.profile或.bash_profile中的 export 可能未生效 - 修改配置文件后,要
source ~/.bashrc或新开终端,否则当前 shell 还是旧环境
调试继承是否成功的方法
不用猜,直接看子进程到底拿到了什么。
- 在子 shell 中运行
env | grep -E '^(PATH|HOME|MYVAR)=',确认变量是否存在且值正确 - 用
ps -f查看进程树,确认父子关系是否符合预期(比如你启动的程序确实是目标 shell 的直系子进程) - 写个简单 C 程序,用
extern char **environ;遍历并打印全部环境变量,最可靠


















