Linux exec函数族完全指南

在 Linux 系统编程中,exec 函数族 用于在一个进程中替换当前运行的程序为另一个新的程序。它与 fork() 配合使用,是实现多进程编程、启动子进程执行外部命令的核心机制。


目录

一、exec 函数族概述

二、exec 函数族成员

三、函数原型详解

1. execl()

示例:

2. execlp()

示例:

3. execv()

示例:

4. execvp()

示例:

5. execle()

示例:

四、exec 执行流程图解(知识树状图)

五、exec 的使用场景

1. 在子进程中执行新程序

示例代码:

编译运行:

六、exec 返回值说明

七、exec 与 fork 的经典组合模式

八、exec 的高级用法

1. 使用 exec 替换当前 shell 进程

2. 重定向标准输入输出后执行

九、总结知识点图解(知识树状图)

十、课后练习建议


一、exec 函数族概述

exec 并不是一个单独的函数,而是一组具有相似功能的系统调用,它们的功能都是将当前进程映像替换为一个新的可执行文件(如 /bin/ls, /usr/bin/python 等)。

注意: exec 不会创建新进程,而是替换当前进程的代码段、数据段、堆栈等,因此调用成功后不会返回原程序。


二、exec 函数族成员

以下是常见的六个 exec 函数(定义在 中):

函数名 参数形式 是否使用环境变量 PATH
execl() 列表(参数逐个传入)
execlp() 列表 是(自动查找 PATH)
execv() 数组(char *argv[])
execvp() 数组
execle() 列表 + 指定环境变量
execvpe()(非标准) 数组 + 指定环境变量

三、函数原型详解

1. execl()

int execl(const char *path, const char *arg0, ..., /* (char *) NULL */);
  • path:要执行的程序路径(绝对或相对)
  • arg0, arg1, ...:程序的命令行参数,以 NULL 结束
示例:
execl("/bin/ls", "ls", "-l", NULL);

2. execlp()

int execlp(const char *file, const char *arg0, ..., /* (char *) NULL */);
  • file:程序名(不带路径也可,会搜索 PATH)
  • 其他参数同上
示例:
execlp("ls", "ls", "-a", NULL);

3. execv()

int execv(const char *path, char *const argv[]);
  • argv[]:一个指向参数字符串数组的指针,最后一个元素必须为 NULL
示例:
char *args[] = {"ls", "-l", "/home", NULL};
execv("/bin/ls", args);

4. execvp()

int execvp(const char *file, char *const argv[]);
  • 类似 execv(),但支持 PATH 环境变量查找
示例:
char *args[] = {"python3", "script.py", NULL};
execvp(args[0], args);

5. execle()

int execle(const char *path, const char *arg0, ..., /* (char *) NULL, char * const envp[] */);
  • 可自定义环境变量
示例:
char *env[] = {"PATH=/bin:/usr/bin", "USER=test", NULL};
execle("/bin/echo", "echo", "Hello World", NULL, env);

四、exec 执行流程图解(知识树状图)

+----------------------------+
|        当前进程            |
+----------------------------+
           |
           v
+----------------------------+
|     调用 exec 函数         |
|  如:execl(), execv() 等    |
+----------------------------+
           |
           v
+----------------------------+
|  内核加载并执行新程序      |
| (替换当前进程的代码和数据)|
+----------------------------+
           |
           v
+----------------------------+
| 新程序开始运行              |
| 原进程上下文被完全替换      |
+----------------------------+

五、exec 的使用场景

1. 在子进程中执行新程序

这是最常见的使用方式:先 fork() 创建子进程,然后在子进程中调用 exec 执行新程序。

示例代码:
#include 
#include 
#include 
#include 

int main() {
    pid_t pid = fork();

    if (pid < 0) {
        perror("Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process is about to exec ls -l\n");
        execl("/bin/ls", "ls", "-l", NULL);

        // 如果 exec 成功,下面这句不会执行
        perror("exec failed");
        return 1;
    } else {
        // 父进程等待子进程结束
        wait(NULL);
        printf("Parent: Child process finished.\n");
    }

    return 0;
}

编译运行:

gcc exec_example.c -o exec_example
./exec_example

输出示例:

Child process is about to exec ls -l
total 8
-rwxr-xr-x 1 user user 8672 Jul 4 10:00 exec_example
Parent: Child process finished.

六、exec 返回值说明

  • 如果成功:永远不会返回(因为当前进程已经被新程序替代)
  • 如果失败:返回 -1,并设置 errno 错误码

常见错误包括:

errno 值 含义
ENOENT 文件不存在
EACCES 权限不足
ENOMEM 内存不足
ELOOP 解析路径时遇到循环符号链接
ETXTBSY 程序正在被执行,无法修改

七、exec 与 fork 的经典组合模式

父进程
   |
   v
fork()
   ├─→ 父进程继续执行(通常调用 wait 等待)
   └─→ 子进程调用 exec 执行新程序

这种模式是构建 shell、守护进程、服务管理器等程序的基础。


八、exec 的高级用法

1. 使用 exec 替换当前 shell 进程

在 Shell 脚本中也可以使用 exec 来替换当前 shell:

#!/bin/bash
exec python3 myscript.py

脚本运行后,bash 进程会被 Python 替换。

2. 重定向标准输入输出后执行

exec > output.txt
exec /bin/ls -l

这样 ls 的输出会被写入到 output.txt


九、总结知识点图解(知识树状图)

exec 函数族
│
├── 功能:替换当前进程为新程序
│
├── 常见函数
│   ├── execl(), execlp()
│   ├── execv(), execvp()
│   ├── execle(), execvpe()
│
├── 参数传递方式
│   ├── 列表(execl 系列)
│   └── 数组(execv 系列)
│
├── 环境变量控制
│   ├── 默认继承当前环境变量
│   └── 可通过 execle 等指定新环境
│
├── 成功执行后不会返回
│
├── 最佳实践
│   ├── fork() 创建子进程
│   └── exec() 替换子进程执行新程序
│
└── 错误处理
    ├── 必须检查返回值
    └── 失败时返回 -1,并设置 errno

十、课后练习建议

  1. 编写一个程序,在子进程中调用 exec 执行 ps aux,观察输出。
  2. 使用 execv() 实现一个简单的 shell 命令解析器(输入命令后执行)。
  3. 尝试在 Shell 脚本中使用 exec 替换当前进程为 Python 或其他语言解释器。
  4. 编写一个程序故意触发 exec 失败(如执行不存在的程序),并打印对应的 errno 和错误信息。
  5. 使用 strace 跟踪 exec 的系统调用行为:
strace -f ./your_exec_program

你可能感兴趣的:(Linux exec函数族完全指南)