1. exec 函数族概述exec 函数族是 Linux/Unix 系统中用于进程控制的核心函数之一其主要功能是用指定的程序替换当前进程的内存映像。1.1 核心概念进程替换调用 exec 函数后当前进程的代码段、数据段、堆栈等都被新程序完全替换进程标识保留进程 IDPID、父进程 ID、优先级等属性保持不变文件描述符默认情况下打开的文件描述符会被继承除非设置了 FD_CLOEXEC 标志1.2 典型应用场景Shell 命令执行当你在终端输入ls时Shell 会 fork 子进程然后 execls程序服务器进程管理守护进程 fork 子进程处理请求子进程 exec 具体的服务程序程序加载器动态加载并执行其他可执行文件2. exec 函数族分类exec 函数族包含 6 个主要函数它们都声明在unistd.h头文件中#includeunistd.hintexecl(constchar*path,constchar*arg,...);intexeclp(constchar*file,constchar*arg,...);intexecle(constchar*path,constchar*arg,...,char*constenvp[]);intexecv(constchar*path,char*constargv[]);intexecvp(constchar*file,char*constargv[]);intexecve(constchar*path,char*constargv[],char*constenvp[]);2.1 命名规则解析llist参数以可变参数列表形式传递最后一个参数必须是NULLvvector参数以字符串数组argv[]形式传递ppath在PATH环境变量指定的目录中搜索可执行文件eenvironment可以指定自定义的环境变量数组2.2 返回值说明成功不返回进程已被新程序替换失败返回 -1并设置errno原进程继续执行3. execl 和 execlp 函数3.1 函数原型intexecl(constchar*path,constchar*arg,...);intexeclp(constchar*file,constchar*arg,...);3.2 参数说明pathexecl可执行文件的完整路径fileexeclp可执行文件名系统会在PATH环境变量中查找arg…可变参数列表第一个参数通常是程序名最后必须以NULL结束3.3 使用示例执行 ls 命令#includestdio.h#includeunistd.h#includeerrno.hintmain(){// 使用 execl - 需要指定完整路径printf(使用 execl 执行 ls 命令...\n);if(execl(/bin/ls,ls,-l,-a,/etc,NULL)-1){perror(execl 执行失败);return1;}// 这行代码不会被执行除非 execl 失败printf(这行不会输出\n);return0;}#includestdio.h#includeunistd.hintmain(){// 使用 execlp - 自动在 PATH 中查找printf(使用 execlp 执行 ls 命令...\n);if(execlp(ls,ls,-l,-a,/etc,NULL)-1){perror(execlp 执行失败);return1;}return0;}3.4 区别对比特性execlexeclp路径查找必须提供完整路径自动在 PATH 中查找使用便捷性较低需知道路径较高类似命令行安全性较高路径明确较低可能受 PATH 篡改影响4. execv 和 execvp 函数4.1 函数原型intexecv(constchar*path,char*constargv[]);intexecvp(constchar*file,char*constargv[]);4.2 参数说明argv[]字符串指针数组包含所有参数argv[0]通常是程序名最后一个元素必须是NULL指针4.3 使用示例#includestdio.h#includeunistd.hintmain(){// 准备参数数组char*args[]{ls,-l,-a,/etc,NULL};// 使用 execv - 需要完整路径printf(使用 execv 执行 ls 命令...\n);if(execv(/bin/ls,args)-1){perror(execv 执行失败);return1;}return0;}#includestdio.h#includeunistd.hintmain(){// 准备参数数组char*args[]{ls,-l,-a,/etc,NULL};// 使用 execvp - 自动查找printf(使用 execvp 执行 ls 命令...\n);if(execvp(ls,args)-1){perror(execvp 执行失败);return1;}return0;}4.4 适用场景动态参数当参数数量或内容在运行时确定时封装调用便于将参数封装为数组传递批量处理适合需要处理多个相似命令的情况5. execle 和 execve 函数5.1 函数原型intexecle(constchar*path,constchar*arg,...,char*constenvp[]);intexecve(constchar*path,char*constargv[],char*constenvp[]);5.2 环境变量控制#includestdio.h#includeunistd.hintmain(){char*env[]{PATH/usr/local/bin:/usr/bin:/bin,HOME/home/user,MYVARcustom_value,NULL};char*args[]{env,NULL};// 使用自定义环境变量执行 env 命令if(execve(/usr/bin/env,args,env)-1){perror(execve 执行失败);return1;}return0;}6. system 函数6.1 函数原型#includestdlib.hintsystem(constchar*command);6.2 工作原理调用fork()创建子进程子进程中调用execl(/bin/sh, sh, -c, command, NULL)父进程调用wait()等待子进程结束6.3 使用示例#includestdio.h#includestdlib.hintmain(){printf(使用 system 执行命令...\n);intretsystem(ls -la /etc | head -5);if(ret-1){perror(system 调用失败);}elseif(WIFEXITED(ret)){printf(命令退出状态: %d\n,WEXITSTATUS(ret));}return0;}6.4 与 exec 的区别特性exec 函数族system 函数进程替换是当前进程被替换否创建新进程执行控制权不返回除非失败返回命令执行状态Shell 解析无直接执行程序有通过/bin/sh -c安全性较高无 Shell 注入风险较低可能受 Shell 特性影响使用便捷性较低需处理参数较高类似命令行7. 实战fork exec 模式7.1 典型模式#includestdio.h#includeunistd.h#includesys/wait.h#includestdlib.hintmain(){pid_tpidfork();if(pid0){perror(fork 失败);exit(1);}elseif(pid0){// 子进程执行 ls 命令printf(子进程 PID: %d\n,getpid());char*args[]{ls,-l,/tmp,NULL};if(execvp(ls,args)-1){perror(execvp 失败);exit(1);}}else{// 父进程等待子进程结束printf(父进程 PID: %d创建子进程 PID: %d\n,getpid(),pid);intstatus;waitpid(pid,status,0);if(WIFEXITED(status)){printf(子进程正常退出状态码: %d\n,WEXITSTATUS(status));}}return0;}