“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