首页 > 其他分享 >exec函数族

exec函数族

时间:2022-11-26 15:00:26浏览次数:59  
标签:函数 exec int pid 参数 getpid 进程 环境变量

“exec函数族提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了”

execl   execlp     execle

execv  execvp    execve  

l(list)           参数地址列表,以空指针结尾 v(vector)     存有各参数地址的指针数组的地址 p(path)       代表到环境变量PATH中查找 e(environment)       表示给程序新的环境变量 

 

我是这么理解的,就是这几个函数共有部分的是exec,所以在exec后面加了哪个字母这个函数就会具有哪个功能或者性质

比如execlp后面多了l、p,那这个函数就是要列出各个参数+自动按PATH环境变量中的路径去查找指定文件

 

 

可以使用man命令查询:man 3 execve

 

 

 

参数说明: path:要执行的程序路径。可以是绝对路径或者是相对路径。在execv、execve、execl和execle这4个函数中,使用带路径名的文件名作为参数。   file:要执行的程序名称。如果该参数中包含“/”字符,则视为路径名直接执行;否则视为单独的文件名,系统将根据PATH环境变量指定的路径顺序搜索指定的文件。   arg:执行可执行文件所需要的参数列表第一个参数一般没有什么作用,为了方便,一般写的是执行的程序的名称   envp:带有该参数的exec函数可以在调用时指定一个环境变量数组。其他不带该参数的exec函数则使用调用进程的环境变量。   argv:命令行参数的矢量数组。   …:命令行参数列表。调用相应程序时有多少命令行参数,就需要有多少个输入参数项。注意:在使用此类函数时,在所有命令行参数的最后应该增加一个空的参数项(NULL),表明命令行参数结束。(这里NULL相当于一个哨兵) - 返回值:
只有当调用失败,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值     挑几个讲吧 以下所有内容路径:     hello可执行文件是在目录/home/lxq/linux/cv2/目录下     其它文件皆在/home/lxq/linux/lesson1/目录下    hello.c文件:

 

 

1.execl 其实l可以和v一起记, l对应list就是要把那些参数一个个都列出来 v对应vector就是把那些参数都装进一个数组里

 execl.c文件代码:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 int main() {
 6     pid_t id = fork();
 7     
 8     if (id > 0) {
 9         printf ("I am parent process,pid : %d\n",getpid());
10     } else if (id == 0){
11         printf ("I am child process,pid : %d\n",getpid());
12         int ret = execl("/home/lxq/linux/cv2/hello","hello",NULL);
13         if (ret == -1)
14           perror("execl");
15     }
16 
17     int i;
18     for (i = 0; i < 3; ++ i)
19       printf ("%d pid:%d\n",i,getpid());
20 
21     return 0;
22 }

感觉图片比代码块看起来清晰一些

 

 

运行结果:

 

 结果分析:因为execl函数调用成功,所以子进程打印了“Hello,World!”,并且没有执行下面的for循环

如果调用失败,会执行for循环,就是下面这个:

 

 

 

question 在正确输出那里有这样一行:

 

 为什么会这样呢?

 原因:跟孤儿进程有关,一般一个进程启动 会切到后台运行,需要输出时会切换到前台 ,父进程死亡后要切换到前台,就会打印出系统提示符; 而此时子进程还没有结束(变成孤儿进程),还在输出,就出现了这种情况。

那为什么父子进程会在同一个终端输出:因为子进程是父进程fork出来的,内核区某些文件是共享的 ,比如文件描述符表,因为子进程的文件描述符表是拷贝的父进程的,所以二者文件描述符表前三个描述符0(标准输入),1(标准输出),2(标准错误)是一样的 指向的同一片区域,所以也就会在同一个终端输出啦  

解决办法:

让父进程睡眠几秒,这样父进程就不会在子进程前结束,也就不会出现这种情况啦 (后面代码中都有写)

 

2.execv

和execl唯一的区别就是后面的参数一起装一个数组里了

代码:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 int main() {
 6     pid_t id = fork();
 7     
 8     if (id > 0) {
 9         printf ("I am parent process,pid : %d\n",getpid());
10         sleep(1);
11     } else if (id == 0){
12         printf ("I am child process,pid : %d\n",getpid());
13         char *arg[] = {"hello",NULL};
14         int ret = execv("/home/lxq/linux/cv2/hello",arg);
15         if (ret == -1)
16           perror("execv");
17     }
18 
19     int i;
20     for (i = 0; i < 3; ++ i)
21       printf ("%d pid:%d\n",i,getpid());
22 
23     return 0;
24 }

 

 

运行结果:

 

结果分析:因为execv函数调用成功,所以子进程打印了“Hello,World!”,并且没有执行下面的for循环

 

3.execlp

这个就是在execl的基础上加了一个p,函数会自动查询环境变量PATH

execlp.c文件代码:

 1 #include <stdio.h>PATH
 2 #include <unistd.h>
 3 
 4 
 5 int main() {
 6     pid_t id = fork();
 7     
 8     if (id > 0) {
 9         printf ("I am parent process,pid : %d\n",getpid());
10         sleep(1);
11     } else if (id == 0){
12         printf ("I am child process,pid : %d\n",getpid());
13         int ret = execlp("ls","ls","-a",NULL);
14         if (ret == -1)
15           perror("execlp");
16     }
17 
18     int i;
19     for (i = 0; i < 3; ++ i)
20       printf ("%d pid:%d\n",i,getpid());
21 
22     return 0;
23 }

 

 

运行结果:

 

结果分析:因为execlp函数调用成功,所以执行了ls命令并且打印了出来。并且没有执行后面的for循环

这里注意:p是指在环境变量PATH中查找文件,所以可以直接写文件名而不用写路径,因为系统会自动到PATH中查找相关文件的路径,但是!如果你的可执行文件的目录没有在系统环境变量中,这个函数会调用失败,因为在路径中找不到文件。下面举一个例子:

输出:

如果你说你这样没有出错 那就是因为你要打开的文件刚好就在你执行命令的这个目录下面,也就是说你恰好这个相对路径对上了

 

4.execve

注意这个函数第一个参数是path!有些地方写的file是错的

代码:

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 int main() {
 6     pid_t id = fork();
 7     
 8     if (id > 0) {
 9         printf ("I am parent process,pid : %d\n",getpid());
10         sleep(1);
11     } else if (id == 0){
12         printf ("I am child process,pid : %d\n",getpid());
13         char *arg[] = {"hello",NULL};
14         char *envp[] = {"/home/lxq/linux/cv2", NULL};
15         int ret = execve("/home/lxq/linux/cv2/hello",arg,envp);
16         if (ret == -1) 
17           perror("execve");
18     }
19 
20     int i;
21     for (i = 0; i < 3; ++ i)
22       printf ("%d pid:%d\n",i,getpid());
23 
24     return 0;
25 }

 

 

运行结果:

 

结果分析:因为execve函数调用成功,所以子进程打印了“Hello,World!”,并且没有执行下面的for循环

 

在末尾想说一下execlp和execle,有助于理解e的作用吧 ,可以看下这篇文章Linux exec族函数解析 - schips - 博客园 (cnblogs.com)

execlp函数使执行码重生时继承了Shell进程的所有环境变量,其他三个不以e结尾的函数同理。

利用函数execle,可以将环境变量添加到新建的子进程中去。

使用execle和execve可以自己向执行进程传递环境变量,但不会继承Shell进程的环境变量,而其他四个exec函数则继承Shell进程的所有环境变量。

理解这里的关键就是你要理解利用exec系列函数 是在“重生”一个进程

 

标签:函数,exec,int,pid,参数,getpid,进程,环境变量
From: https://www.cnblogs.com/balabalabubalabala/p/16923182.html

相关文章