在有些场景中我们需要创建一个进程,让该进程来帮我们完成某项工作,比如Linux中的shell,shell就是一个进程,他通过不断创建子进程,通过让子进程来帮我们执行程序。
程序替换只是将替换的进程加载到内存中,然后修改当前进程的映射信息,完成替换,程序替换并不会创建新的进程。
在linux中程序替换是通过exec函数族完成的。
int execl(const char *path, const char *arg, …); |
---|
int execlp(const char *file, const char *arg, …); |
int execle(const char *path, const char *arg, …, char * const envp[]); |
int execv(const char *path, char *const argv[]); |
int execvp(const char *file, char *const argv[]); |
int execvpe(const char *file, char *const argv[],char *const envp[]); |
返回值:函数仅在发生错误时返回,返回值为-1; |
exec函数族都是以exec开头,后面的每个字母都有不同的含义
- l(list):表示参数采用列表的形式(一一列出来)。
- v(vector):表示参数参数采用数组的形式。
- p(path):会在环境变量PATH中进行找需要替换的程序(不需要填写程序的路径)。
- e(env):可以传入自己的环境变量。
execl("/usr/bin/ls","ls","-al",NULL);
- 第一个参数为替换程序的路径,因为该函数不带P,所以就需要填写替换程序的路径。
- 第二个参数为如何执行这个程序,也就是在命令行上你是怎么样运行它的,将参数一一列举出来,在最后写一个NULL,表示结尾。
execlp("ls","ls","-al",NULL);
这个函数和上面的execl唯一的区别就是这个函数多一个p,就表示当前函数进行替换时,替换的程序如果在PATH环境变量中,就可以不用在填写路径。
char* argv[]={"ls","-al",NULL};
execv("/usr/bin/ls",argv);
v表示参数以数组的形式进行传参,所以我们定义了一个指针数组,数组中存放的就是一条一条的命令,最后也是也NULL结尾。
char* argv[]={"ls","-al",NULL};
execvp("ls",argv);
带V和P说明了,可以不用传文件的路径,参数以列表的形式。
char* const env[]={"hello","world",NULL};
execle("a.out","ls","-al",NULL,env);
e表示我们可以给替换的程序传入环境变量,这个我们就传入一个自定义的环境变量,同样环境变量最后也是也NULL结尾。
#include
int main()
{
extern char** environ;
for(int i = 0;environ[i];i++)
{
printf("%s\n",environ[i]);
}
return 0;
}
#include
#include
int main()
{
char* const env[]={"hello","world",NULL};
execle("a.out","ls","-al",NULL,env);
//这里要替换的a.out和当前程序在一个目录下,所以没有写全路径。
return 0;
}
在上面的代码中我们给替换的程序传入一个环境变量,而替换的那个程序的工作就是打印当前进程的环境变量。
execve("a.out",argv,env);
同样的我们可以使用数组的形式来传递参数。
在Linux中上面的6个函数只有execve是系统调用,其他的5个函数都是库函数,他们对应的关系如下