「Linux 系统编程」exec 函数族及使用示例
1 exec 函数族
在 Linux 系统编程中,fork()
函数用于创建一个新的进程,这个新进程是当前进程的副本。如果我们想要新进程执行一个全新的、不同的程序,这个时候就需要用到 exec
函数族。
exec
是 Linux 中一组功能强大且常用的函数,负责将当前进程的镜像替换为一个新的程序镜像 —— 进程的 PID 保持不变,但运行的程序被彻底替换。
1.1 exec 函数族概览
exec
函数族包含了多个函数,它们的核心功能相同(加载新程序),在参数传递方式上略有差异。这些函数都定义在 <unistd.h>
中。
函数原型 | 参数特点 | 路径搜索 | 环境变量 |
---|---|---|---|
int execl(const char *path, const char *arg, ...); |
列表 (List) | 否 (需全路径) | 继承父进程 |
int execlp(const char *file, const char *arg, ...); |
列表 (List) | 是 (PATH) | 继承父进程 |
int execle(const char *path, const char *arg, ..., char *const envp[]); |
列表 (List) | 否 (需全路径) | 自定义 |
int execv(const char *path, char *const argv[]); |
向量 (Vector/数组) | 否 (需全路径) | 继承父进程 |
int execvp(const char *file, char *const argv[]); |
向量 (Vector/数组) | 是 (PATH) | 继承父进程 |
int execvpe(const char *file, char *const argv[], char *const envp[]); |
向量 (Vector/数组) | 是 (PATH) | 自定义 |
注意:
execvpe
是一个 GNU 扩展,并非所有 UNIX 系统都支持(但主流 Linux 发行版都支持)。
区分 exec
函数族每个函数:
l
(list):以列表的形式设置命令行参数p
(path):搜索 file 时使用 path 变量v
(vector):以数组的形式设置命令行e
(environment):使用环境变量数组,不适用进程原有的环境变量,设置新加载程序运行的环境变量
1.2 exec 函数参数
-
const char *file
/const char *path
:执行的程序。如果是file
需要借助 PATH 环境变量寻找待执行程序;如果是path
必须是完整的路径。 -
const char *arg, ...
:对应的分别是命令行参数的argv[0], argv[1], argv[2], ...
,并且最后需要添加一个NULL
表示参数结束。 -
char *const argv[]
:与const char *arg, ...
同理,参数数组的最后必须以NULL
结尾。
1.3 exec 函数返回值
exec
函数一旦调用成功,即执行新的程序,不返回。exec
只有失败才返回,返回-1
。因此通常直接在exec
函数调用后直接调用perror()
等错误判断。
2 execl、execlp (参数列表形式)
2.1 函数原型
1 |
|
-
path/file
: 要执行的程序的路径。execl
需要 绝对路径 或 相对路径(如/bin/ls
或./my_program
)。execlp
只需要 程序名,系统会在$PATH
环境变量指定的目录中搜索该程序。
-
arg0, arg1, ...
: 命令行参数列表。arg0
是程序名本身(argv[0]
)。 -
...
: 参数需要以(char *) NULL
结尾,表示参数列表结束。
2.2 代码示例
-
使用
execl
执行ls -lh
1
2
3
4
5
6
7
8
9#include <unistd.h>
int main(){
execl("/bin/ls", "ls", "-l", "-h", (char*)NULL);
// execl 失败才会执行后续代码
perror("execl error");
return 1;
}
-
使用
execlp
执行ps aux
:1
2
3
4
5
6
7
8
9
10#include <unistd.h>
int main(){
// 系统会在 PATH 中找到 "ps" 命令
execlp("ps", "ps", "aux", (char*)NULL);
// execlp 失败才会执行后续代码
perror("execlp failed");
return 1;
}
3 execv、execvp (参数数组形式)
3.1 函数原型
1 |
|
-
path/file
: 同execl/execlp
。 -
argv[]
: 一个字符串指针数组,包含了所有命令行参数。该数组的最后一个元素必须是NULL
。
3.2 代码示例
使用 execvp
执行 ls -l /home/[username]
1 |
|
4 execle、execvpe (自定义环境变量)
4.1 函数原型
1 |
|
envp[]
: 一个字符串指针数组,代表新程序的环境变量。数组以NULL
结尾。每个字符串的格式通常是 “KEY=VALUE”。
envp[]
为新的程序进程提供一个 完全自定义的环境,而不是继承父进程的环境。
4.2 代码示例
使用 execle
执行一个程序并传递自定义环境
1 |
|
1 |
|
print_env
程序只是打印它的所有环境变量,只会看到 MY_VAR
和 PATH
,而看不到父进程原有的其他环境变量。
5 fork() 结合 exec 调用新程序
5.1 exec 核心特性
-
exec
调用成功,当前进程的代码、数据、堆、栈等所有段都被新程序彻底覆盖。exec
之后的代码永远不会被执行(除非调用失败)。 -
进程的 PID、PPID(父进程ID)、文件描述符、信号处理方式等属性会被保留。新程序可以继承父进程打开的文件、网络连接等资源。
fork() 结合 exec 代码示例
exec
最常见的用法是与 fork()
结合:
- 父进程调用
fork()
创建子进程。 - 子进程调用
exec()
来执行另一个程序。 - 父进程通常调用
wait()
来等待子进程结束。
1 |
|