1. 函数族
exec函数族,是由六个exec函数组成的。
- exec函数族提供了六种在进程中启动另一个程序的方法。
- exec函数族可以根据指定的文件名或目录名找到可执行文件。
- 调用exec函数的进程并不创建新的进程,故调用exec前后,进程的进程号并不会改变,其执行的程序完全由新的程序替换,而新程序则从其main函数开始执行。
exec函数族取代调用进程的数据段、代码段和堆栈段
注意:一个进程调用exec后,除了进程ID,进程还保留了下列特征不变:父进程号、进程组号、控制终端、根目录、当前工作目录、进程信号屏蔽集、未处理信号
2. exec函数
需要的头文件
#include <unistd.h>
函数结构:
- int execl(const char *path, const char *arg, .../* (char *) NULL */);
- int execlp(const char *file, const char *arg, .../* (char *) NULL */);
- int execle(const char *path, const char *arg, .../*, (char *) NULL*/, cha r * const envp[ ] );
- int execv(const char *path, char *const argv[ ]);
- int execvp(const char *file, char *const argv[ ]);
- int execve(const char *file, char *const argv[ ], char *const envp[ ]);
注意:6个exec函数中只有execve是真正意义的系统调用(内核提供的接口),其它函数都是在此基础上经过封装的库函数
3. 后缀的意义
- l (list):参数地址列表,以空指针结尾;参数地址列表:char *file(), char *arg1, ... char *argn NULL
- v (vector):存有各参数地址的指针数组的地址;使用时先构造一个指针数组,指针数组存在各参数的地址,然后将该指针数组地址作为函数的参数
- p (path):按PATH环境变量指定目录搜索可执行文件;以p结尾的exec函数取文件名作为参数,当指定filename作为参数时,若filename中包含/,则将其视为路径名,并直接到指定的路径中执行程序。
- e (environment):存有环境变量字符串地址的指针数组的地址,execle和execve改变的是exec启动的程序的环境变量(新的环境变量完全由environment指定),其它四个函数启动的程序则使用默认系统环境变量。
注意:exec函数族和一般的函数不同,exec函数族中的函数执行成功后不会返回。只有调用失败后,他们才会返回-1。失败后从原程序的调用点接着往下执行,在平时的编程中,如果用到了exec函数族,一定要记得加上错误判断语句。
代码展示:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
pid_t pid;
if((pid = fork()) < 0)
{
perror("fail to fork");
exit(1);
}
else if(pid > 0) //父进程
{
printf("This is parent process\n");
wait(NULL);
printf("The child process has quited\n");
}
else //子进程
{
printf("This is child process\n");
//调用exec函数族中的函数,执行其他命令或者程序
//查看命令的路径:whereis 命令或者which 命令
//***************exec函数族调用shell命令******************
//不带p的函数,命令的路径一定要用绝对路径
#if 0
if(execl("/bin/ls", "ls", "-l", NULL) == -1)
{
perror("fail to execl");
exit(1);
}
#endif
//带p的函数,第一个参数既可以是相对路径,也可以是绝对路径
#if 0
if(execlp("ls", "ls", "-l", NULL) == -1)
{
perror("fail to execlp");
exit(1);
}
#endif
//带v的函数需要使用指针数组来传递
#if 0
char *str[] = {"ls", "-l", NULL};
if(execv("/bin/ls", str) == -1)
{
perror("fail to execv");
exit(1);
}
#endif
//***************exec函数族调用可执行文件******************
#if 0
if(execlp("./hello", "./hello", NULL) == -1)
{
perror("fail to execlp");
exit(1);
}
#endif
#if 0
if(execl("./hello", "./hello", NULL) == -1)
{
perror("fail to execl");
exit(1);
}
#endif
//***************exec函数族调用shell脚本******************
#if 1
if(execlp("./myshell.sh", "./myshell.sh", NULL) == -1)
{
perror("fail to execl");
exit(1);
}
#endif
//exec函数族取代调用进程的数据段、代码段和堆栈段
//所以当exec函数执行完毕后,当前进程就结束了,所以原本进程中的代码不会再执行
printf("hello world\n");
}
return 0;
}