1. exec函数说明

fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程不共享这些存储空间。linux将复制父进程的地址空间内容给子进程,因此,子进程由了独立的地址空间。),也就是这两个进程做完全相同的事。

在fork后的子进程中使用exec函数族,可以装入和运行其它程序(子进程替换原有进程,和父进程做不同的事)。

exec函数族可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。在执行完后,原调用进程的内容除了进程号外,其它全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。

2.在Linux中使用exec函数族主要有一下两种情况

  • 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec函数族让自己重生;
  • 如果一个进程想执行另外一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生;

3.exec函数族语法

实际上,在Linux中并没有exec函数,而是有6个以exec开头的函数族,下表列举了exec函数族的6个成员函数的语法。

这6个函数在函数名和使用语法的规则上都有细微的区别,下面就可执行文件查找方式、参数传递方式及环境变量这几个方面进行比较说明。

  • 查找方式:上表中前4个函数的查找方式都是完整的文件目录路径(即绝对路径),而最后两个函数(也就是以p结尾的两个函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。
  • 参数传递方式:有两种方式,一种是逐个列举的方式,另一种是将所有参数整体构造成一个指针数组进行传递。(在这里,字母“l”表示逐个列举的方式,字母“v”表示将所有参数整体构造成指针数组进行传递,然后将该数组的首地址当做参数传递给它,数组中的最后一个指针要求时NULL)
  • 环境变量:exec函数族使用了系统默认的环境变量,也可以传入指定的环境变量。这里以“e”结尾的两个函数就可以在envp[]中指定当前进程所使用的环境变量替换掉该进程继承的所有环境变量。

3.PATH环境变量说明

PATH环境变量包含了一张目录表,系统通过PATH环境变量定义的路径搜索执行码,PATH环境变量定义时目录之间需用“;”分隔,以“.”表示结束 。PATH环境变量定义在用户的.profile或.bash_profile中,下面是PATH环境变量定义的样例,此PATH环境变量指定“/bin”、“/usr/bin”和当前目录三个目录进行 搜索执行码。

PATH=/bin:/usr/bin..

export $PATH

4.进程中的环境变量说明

在Linux中,Shell进程是所有执行码的父进程。当一个执行码执行时,Shell进程会fork子进程然后调用exec函数去执行执行码。Sehll进程堆栈中存放着该用户下的所有环境变量,使用不带“e”的4个函数使执行码重生时,Shell进程会将所有环境变量复制给生成的新进程;而使用带“e”的两个函数时新进程不继承任何Shell进程的环境变量,而由envp[]数组自行设置环境变量。

5.exec函数族关系

事实上,这6个函数中真正的系统调用只有execve,其他5个都是库函数,它们最终都会调用execve这个系统调用,调用关系如下图所示:

6.exec函数族调用举例如下

char *const ps_argv[] = {"ps", "-o", "pid, ppid, session, tpgid, comm, NULL"};

char *const ps_envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};

execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);

execv("/bin/ps", ps_argv);

execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);

execve("/bin/ps", ps_argv, ps_envp);

execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);

execvp("ps", ps_argv);

请注意exec函数族形参展开时的前两个参数,第一个参数是带路径的执行码(execlp、execvp函数第一个参数是无路径的,系统会根据PATH自动查找然后合成带路径的执行码),第二个是不带路径的执行码,执行码可以是二进制执行码和Shell脚本。

7.exec函数族使用注意点

在使用exec函数族时,一定要加上错误判断语句。因为exec很容易执行失败,其中最常见的原因有:

  • 找不到文件或路径,此时errno被设置为ENOENT。
  • 数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT。
  • 没有对用可执行文件的运行权限,此时errno被设置为EACCES。

8.exec后新进程保持原进程以下特征

环境变量(使用了execle、execve函数则不继承环境变量);

Ÿ进程ID和父进程ID;

实际用户ID和实际组ID;

附加组ID;

进程组ID;

会话ID;

控制终端;

当前工作目录;

根目录;

文件权限屏蔽字;

文件锁;

进程信号屏蔽;

未决信号;

资源限制;

tms_utime、tms_stime、tms_cutime以及tms_ustime值。

对打开文件的处理与每个描述符的exec关闭标志值有关,进程中每个文件描述符有一个exec关闭标志(FD_CLOEXEC),若此标志设置,则在执行exec时关闭该描述符,否则该描述符仍然打开。除非特地用了fcntl设置了该标志,否则系统的默认操作是在exec后仍保持这种描述符打开,利用这一点可以实现I/O重定向。

9.各个函数使用举例

1 #ifdef HAVE_CONFIG_H2 #include <config.h>3 #endif4 5 #include <stdio.h>6 #include <stdlib.h>7 #include <unistd.h>8 #include <string.h>9 #include <errno.h>10 11 int main(int argc, char *argv[])12 {13   //以NULL结尾的字符串数组的指针,适合包含v的exec函数参数14   char *arg[] = {"ls", "-a", NULL};15   16   /**17    * 创建子进程并调用函数execl18    * execl 中希望接收以逗号分隔的参数列表,并以NULL指针为结束标志19    */20   if( fork() == 0 )21   {22     // in clild 23     printf( "1------------execl------------\n" );24     if( execl( "/bin/ls", "ls","-a", NULL ) == -1 )25     {26       perror( "execl error " );27       exit(1);28     }29   }30   31   /**32    *创建子进程并调用函数execv33    *execv中希望接收一个以NULL结尾的字符串数组的指针34    */35   if( fork() == 0 )36   {37     // in child 38     printf("2------------execv------------\n");39     if( execv( "/bin/ls",arg) < 0)40     {41       perror("execv error ");42       exit(1);43     }44   }45   46   /**47    *创建子进程并调用 execlp48    *execlp中49    *l希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志50    *p是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件51    */52   if( fork() == 0 )53   {54     // in clhild 55     printf("3------------execlp------------\n");56     if( execlp( "ls", "ls", "-a", NULL ) < 0 )57     {58       perror( "execlp error " );59       exit(1);60     }61   }62   63   /**64    *创建子里程并调用execvp65    *v 望接收到一个以NULL结尾的字符串数组的指针66    *p 是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件67    */68   if( fork() == 0 )69   {70     printf("4------------execvp------------\n");71     if( execvp( "ls", arg ) < 0 )72     {73       perror( "execvp error " );74       exit( 1 );75     }76   }77   78   /**79    *创建子进程并调用execle80    *l 希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志81    *e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境82    */83   if( fork() == 0 )84   {85     printf("5------------execle------------\n");86     if( execle("/bin/ls", "ls", "-a", NULL, NULL) == -1 )87     {88       perror("execle error ");89       exit(1);90     }91   }92   93   /**94    *创建子进程并调用execve95    * v 希望接收到一个以NULL结尾的字符串数组的指针96    * e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境97    */98   if( fork() == 0 )99   {
100     printf("6------------execve-----------\n");
101     if( execve( "/bin/ls", arg, NULL ) == 0)
102     {
103       perror("execve error ");
104       exit(1);
105     }
106   }
107   return EXIT_SUCCESS;
108 }

运行结果(Linux)

1------------execl------------
.  ..  .deps  exec  exec.o  .libs  Makefile
2------------execv------------
.  ..  .deps  exec  exec.o  .libs  Makefile
3------------execlp------------
.  ..  .deps  exec  exec.o  .libs  Makefile
4------------execvp------------
.  ..  .deps  exec  exec.o  .libs  Makefile
5------------execle------------
.  ..  .deps  .libs  Makefile  exec  exec.o
6------------execve-----------
.  ..  .deps  .libs  Makefile  exec  exec.o

exec函数用法总结相关推荐

  1. Python exec函数用法

    定义和用法 exec() 函数执行指定的 Python 代码. exec() 函数接受大量代码块,这与 eval() 函数仅接受单个表达式不同. 语法 exec(object, globals, lo ...

  2. c++中的fork函数_linux c语言 fork() 和 exec 函数的简介和用法

    linux c语言 fork() 和 exec 函数的简介和用法 假如我们在编写1个c程序时想调用1个shell脚本或者执行1段 bash shell命令, 应该如何实现呢? 其实在<stdli ...

  3. linux c语言 fork() 和 exec 函数的简介和用法

    假如我们在编写1个c程序时想调用1个shell脚本或者执行1段 bash shell命令, 应该如何实现呢? 其实在<stdlib.h> 这个头文件中包含了1个调用shell命令或者脚本的 ...

  4. Linux系统编程18:超详解进程程序替换exec函数的一些用法

    文章目录 (1)进程程序替换是什么 (2)exec-替换函数 (3)实例展示-了解exec函数的替换原理 A:execl和execv B:execlp和execvp C:替换自己的程序和execle ...

  5. linux exec 二程序,二十五、Linux 进程与信号---exec函数

    25.1 介绍 在用 fork 函数创建子进程后,子进程往往要调用一种 exec 函数以执行另一个程序 当进程调用一种 exec 函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其 m ...

  6. cube、rollup及exec的用法实例

    为什么80%的码农都做不了架构师?>>>    cube.rollup及exec的用法实例 select sdept 系部,sno 学号,max(sage) 最大年龄,   grou ...

  7. qt: exec()的用法,accept()和accepted的概念

    转载:http://blog.csdn.net/xdlichen/article/details/46374517 本篇,会重点讲述模式对话框,以及exec()的用法,accept()和accepte ...

  8. Python之浅谈exec函数

      在Python中,exec()是一个十分有趣且使用的内置函数,不同于eval()函数只能执行计算数学表达式的结果的功能,exec()能够动态地执行复杂的Python代码,能够十分强大.具体的介绍可 ...

  9. exec函数族用法总结

    1.exec函数说明 fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的& ...

  10. php system函数用法,system函数如何使用?总结system函数实例用法

    这篇文章主要简单分析了linux下system函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下简单分析了linux下system函数的相关内容,具体内容如下int libc_system (co ...

最新文章

  1. mysql数据库sql语句大全
  2. vs2010 使用STLport-5.2.1
  3. mysql 节点查根_(三)B数、B+树及在数据库索引中应用
  4. 可关闭的浮动div示例
  5. SAP UI5 My Opportunity应用里的 currency validation
  6. [Linux]Ubuntu 以管理员权限打开文件夹
  7. Python 检测字符串开始值String.StartsWith 方法
  8. 佛系听歌?Beats推出“串珠”耳机 盘它?
  9. python环境搭建-pycharm2016软件注册码
  10. 181209每日一句
  11. 什么是动作分析?动作分析的方法有哪些?
  12. android图案解锁忘了怎么解,安卓手机解锁图案忘了怎么办?手机解锁密码忘了怎么办?...
  13. K8S搭建redis集群(2)使用redis-trib
  14. python计算2的n次方编写_python中n次方怎么表示
  15. 无线路由器和有线路由器桥接
  16. linux reboot 实现流程
  17. 个人资料管理经验总结
  18. 高校计算机专业要求选科的科目,新高考省份,想学人工智能专业,该怎么选科?哪种组合最好?(北京、江苏为例)...
  19. 算法工程师0——算法工程师学习进阶路线
  20. 如何学好游戏3D引擎编程

热门文章

  1. 三次函数的对称中心问题
  2. Opencv 统计灰度图所有灰度值
  3. Oracle EBS 笔记8
  4. 13 岁女孩因发布JavaScript被捕,写个死循环你就进去了?
  5. 网页P2P加速视频解析dplayer播放器源码(带记忆播放功能)
  6. 计算机 上的图片怎样加密码,高手加密法之利用图片给电脑加密新招
  7. 数据库 “投毒”修复方案
  8. DQN的e-greedy策略理解
  9. 关于nginx配置负载均衡,nginx.conf配置文件正确,一直跳出nginx欢迎界面
  10. 运用帝国CMS建站仿站的简单教程(初学者进)