exec() 族函数使用
exec() 族函数的核心作用是:替换当前进程的代码段、数据段等内存空间,以新的程序完全替代当前进程的运行内容
| 函数名 | 参数列表形式 | 是否使用 PATH | 环境变量 |
| execl | List(列表) | 否 | 继承当前环境 |
| execlp | List(列表) | 是 | 继承当前环境 |
| execle | List(列表) | 否 | 需自行指定 |
| execv | Vector(数组) | 否 | 继承当前环境 |
| execvp | Vector(数组) | 是 | 继承当前环境 |
| execvpe | Vector(数组) | 是 | 需自行指定 |
List (l): 将命令行参数作为一个个独立的字符指针传入,最后必须以 NULL 结尾。所以所有用到列表作为传入参数方式的函数在exec后都会有个l。
execl("/bin/ls", "ls", "-l", "-a", NULL);Vector (v): 将命令行参数放入一个字符指针数组中,该数组必须以 NULL 结尾。所以所有用到列表作为传入参数方式的函数在exec后都会有个v
char *argv[] = {"ls", "-l", "-a", NULL}; execv("/bin/ls", argv);Path (p): 函数名带 p(如 execlp, execvp)表示系统会在 PATH 环境变量(比如/usr/bin目录下)指定的目录列表中自动搜索名为 file 的可执行文件。不带 p 则必须提供完整路径。函数名带 e(如 execle, execvpe)允许用户自行指定环境变量,通过一个 char *envp[] 数组传递,该数组也必须以 NULL 结尾。不带 e 则新进程继承当前进程的所有环境变量
// 系统会自动在PATH中查找"ls" execlp("ls", "ls", "-l", "-a", NULL); // 需要提供完整路径 execl("/bin/ls", "ls", "-l", "-a", NULL);
比如利用exec函数简单实现一个shell的功能
程序会读取用户输入指令,通过创建的子进程执行execvp函数,去执行一个新程序即我输入的指令。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>#define MAX_ARGS 20int main() {char input[100];char *args[MAX_ARGS];char *token;int i;pid_t pid;int status;while (1) {// 1. 打印提示符,等待用户输入printf("jie shell> ");if (fgets(input, sizeof(input), stdin) == NULL) {break; // 处理 EOF (Ctrl+D)}// 2. 解析输入(简易解析)i = 0;token = strtok(input, " \t\n"); // 用空格、制表符、换行符分割输入while (token != NULL && i < MAX_ARGS - 1) {args[i++] = token;token = strtok(NULL, " \t\n");}args[i] = NULL; // 参数数组必须以NULL结尾if (args[0] == NULL) {continue; // 用户直接回车,继续循环}// 3. 创建子进程pid = fork();if (pid < 0) {perror("fork failed");continue;} else if (pid == 0) {// 4. 子进程:调用 execvp 尝试执行命令execvp(args[0], args);// 如果 execvp 成功,永远不会执行到这里perror("execvp failed"); // 只有失败才会执行exit(EXIT_FAILURE); // 子进程异常退出} else {// 5. 父进程(Shell):等待子进程结束waitpid(pid, &status, 0);// 可以在这里检查子进程的退出状态if (WIFEXITED(status)) {printf("Command exited with status %d\n", WEXITSTATUS(status));}}}return 0;
}
输入不同命令得到结果:

