如果需要在子进程中执行一些自定义的动作,则需要调用 exec 函数族。
当进程调用 exec 系列函数的时候,该进程执行的程序被立即替换为新的程序,而新程序则从 main 函数开始执行,并立刻替换掉了当前进程的正文段、数据段、堆和堆栈,需要注意的是其进程标识符和进程描述符是不会改变的。
1. exec 函数族基础
exec 函数族提供了一个在进程中启动另一个程序执行的方法,其可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。
在 Linux 中通常会在如下两种情况下调用 exec 函数族:
- 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用 exec 函数族中的任
意一个函数让自己重生。 - 如果一个进程想执行另一个程序,那么它就可以调用 fork() 函数新建一个进程,然后调用exec 函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。
对 exec 系列函数的标准调用格式说明如下:
#include <unistd.h>
int execl(const char *path, const char *arg,...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg,...,char * const envp[]);
int execlp(const char *file, const char *arg,...);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
如果这6个函数调用成功则没有返回值,如果出错则返回“-1”, 对其参数说明如下。
- 参数 pathname:指出一个可执行目标文件的路径名。
- 参数 filename:指出可执行目标文件的文件名。
- 参数 arg:作为约定,同 pathname 一样指出目标文件的路径名。
- 参数 argv:是一个字符指针数组,由它指出该目标程序使用的命令行参数表,按照约定第一个字符指针指向与 pathname 或 filename 相同的字符串,最后一个指针指向一个空字符串,其余的指向该程序执行时所带的命令行参数。
- 参数 envp:与 argv 一样也是一个字符指针数组,由它指出该目标程序执行时的进程环境,它也以一个空指针结束。
事实上,这6个函数都是 exec 系列函数经过包装的库函数,它们的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何 Linux 下可执行的脚本文件。
对 exec 系列函数的主要区别说明如下:
- execl 函数、execv 函数、execle 函数、execve 函数使用 pathname 参数,取路径名作为参数;而 execlp 函数和 execvp 函数,取文件名作为参数。
- execl 函数、execle 函数、execlp 函数中的 “l” 字符表示为“list”, 其要求将新程序的每
个命令行参数说明为一个单独的、以空指针为结尾的参数表; execv 函数、execve 函数和execvp 函数中的 “v” 字符表示为 “vector”,其要求先构造一个指向各个参数的指针,然后将该数组地址作为其参数。
execl、execel 和 execlp 这三个函数用于表示命令行参数的一般方式是:
char *arg0, char *arg1,...char *argn, (char *)0
需要注意的是在命令行参数中使用了一个将常数 0 强制转换为空指针的字符指针来作为结尾,如果不进行强制转换,其会被解释为整型参数,从而出现错误。
execle 和 execve 函数中的最后一个字符 “e”表示可以向新的进程传递一个环境变量 envp,对其命令参数说明如下:
char *arg0, char *arg1,...char *argn, (char *)0, char *envp[]
环境变量指的是一组值,这组值从 Linux 用户登录后就一直存在,很多应用程序需要依靠它来确定系统的一些细节,最常见的环境变量是路径(PATH),其指明了应到哪里去搜索相应的应用程序,如/bin;另外 HOME 也是比较常见的环境变量,其指明了用户在系统中的个人目录;环境变量一般以字符串 “XXX=xxx" 的形式存在,XXX 表示变量名,xxx 表示变量的值。
2. exec 函数族的应用
exec 函数族之间的区别和比较。
函数名 | pathname参数 | filename参数 | 参数表 | argv[] | environ参数 | envp[] |
execl函数 | ● | ● | ● | |||
execlp函数 | ● | ● | ● | |||
execle函数 | ● | ● | ● | |||
execv函数 | ● | ● | ● | |||
execvp函数 | ● | ● | ● | |||
execve函数 | ● | ● | ● |
在 exec 系列函数族执行之后,不仅进程的描述符、标识符没有发生改变,该进程的如下特征也将保留:
- 进程标识符和父进程标识符。
- 实际用户ID、实际组ID。
- 附加组ID。
- 进程组ID。
- 会话ID。
- 闹钟剩余时间。
- 控制终端。
- 当前工作目录。
- 根目录。
- 文件模式创建屏蔽字。
- 文件锁。
- 进程信号屏蔽。
- 未处理信号。
- 资源限制。
- tms_utime、 tms_ stime、tms_cutime 以及 tms_ cstime。
应用实例
1. 使用 excel 函数调用 date 命令
2. 使用 execlp 函数调用 ls 命令
3. 使用 execv 函数调用 ls 命令
4. 在父进程和子进程中分别使用 execl 函数