“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系列函数 是在“重生”一个进程

 

原文地址:http://www.cnblogs.com/balabalabubalabala/p/16923182.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性