作者:王姗姗,华清远见嵌入式学院讲师。

exec用被执行的程序完全替换调用它的程序的影像。fork创建一个新的进程就产生了一个新的PID,exec启动一个新程序,替换原有的进程,因此这个新的被exec执行的进程的PID不会改变,和调用exec函数的进程一样。
        下面来看下exec函数族:
        #include <unistd.h>
        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 execve(const char *path, char *const argv[], char *const envp[]);
        exec函数族装入并运行程序pathname,并将参数arg0(arg1,arg2,argv[],envp[])传递给子程序,出错返回-1。在exec函数族中,后缀l、v、p、e添加到exec后,所指定的函数将具有某种操作能力有后缀:

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。
        我们来看下面的一个实例:
        #include <stdio.h>
        #include <unistd.h>
        #include <string.h>
        #include <errno.h>

int main(int argc,char *argv[],char *envp[])
        {
             char *arg[]={"ls","-a",NULL};
             if(fork()==0)
             {
                 printf("execl...........\n");
                 if(execl("/bin/ls","ls","-a",NULL)<0)
                 {
                      fprintf(stderr,"execl failed:%s",strerror(errno));
                      return -1;
                 }
             }
             if(fork()==0)
             {
                 printf("execv...........\n");
                 if(execv("/bin/ls",arg)<0)
                 {
                     fprintf(stderr,"execl failed:%s\n",strerror(errno));
                     return -1;
                 }
             }
             if(fork()==0)
             {
                 printf("execlp...........\n");
                 if(execlp("ls","ls","-a",NULL)<0)
                 {
                     fprintf(stderr,"execl failed:%s",strerror(errno));
                     return -1;
                 }
             }
             if(fork()==0)
             {
                 printf("execvp...........\n");
                 if(execvp("ls",arg)<0)
                 {
                     fprintf(stderr,"execl failed:%s\n",strerror(errno));
                     return -1;
                 }
             }
             if(fork()==0)
             {
                 printf("execle...........\n");
                 if(execle("/bin/ls","ls","-a",NULL,envp)<0)
                 {
                     fprintf(stderr,"execl failed:%s",strerror(errno));
                     return -1;
                 }
             }
             if(fork()==0)
             {
                 printf("execve...........\n");
                 if(execve("/bin/ls",arg,envp)<0)
                 {
                     fprintf(stderr,"execl failed:%s\n",strerror(errno));
                     return -1;
                 }
             }

return 0;
        }
        程序里调用了ls这个Linux常用的系统命令。
        由于各个子进程执行的顺序无法控制,所以有可能出现一个比较混乱的输出--各子进程打印的结果交杂在一起,而不是严格按照程序中列出的次序。
        编译并运行:

下面我们来分析下所写的程序。
        其实我们留心看一下这6个函数,可以发现前3个函数都是以execl开头的,后3个都是以execv开头的。
        首先来比较前两个函数execv和execl。execv开头的函数是把参数以"char *argv[]"这样的形式传递命令行参数。而execl开头的函数采用了我们更容易习惯的方式,把参数一个一个列出来,然后以一个NULL表示结束,也可以写成(char *)0。
        其次紧跟着的2个以p结尾的函数execlp和execvp。与其他几个函数相比,除execlp和execvp之外的4个函数都要求,它们的第1个参数path必须是一个完整的路径,如"/bin/ls";而execlp和execvp的第1个参数file可以简单到仅仅是一个文件名,如"ls",这两个函数可以自动到环境变量PATH制定的目录里去寻找。
        最后两个函数execle和execve,都使用了char *envp[]来传递环境变量。在全部6个函数中,只有execle和execve需要传递环境变量,其它的4个函数都没有这个参数,这并不意味着它们不传递环境变量,这4个函数将把默认的环境变量不做任何修改地传给被执行的应用程序。而execle和execve会用指定的环境变量去替代默认的那些。
        最后要强调一点,大家在平时的编程中,如果用到了exec函数族,一定记得要加错误判断语句。因为与其他系统调用比起来,exec很容易受伤,被执行文件的位置,权限等很多因素都能导致该调用的失败。最常见的错误是:

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

exec函数族的使用的更多相关文章

  1. exec函数族实例解析

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

  2. exec函数族,守护进程,线程同步和互斥

    2015.3.2 进程和程序有三点不同:1,存在位置不同,程序:硬盘,磁盘.进程:内存2. 程序是静态的,进程是动态的 执行./a.out -->bash->bash程序调用fork()- ...

  3. linux exec函数族

    1.简介 在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是: #include <unistd.h>   extern char **environ; ...

  4. Linux进程控制——exec函数族

    原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是 ...

  5. Linux 环境下 fork 函数和 exec 函数族的使用

    前言 接触 Linux 已经有几个月了,以前在网上看各路大神均表示 Windows 是最烂的开发平台,我总是不以为然,但是经过这段时间琢磨,确实觉得 Linux 开发给我带来不少的便利.下面总结一下学 ...

  6. Linux进程实践(3) --进程终止与exec函数族

    进程的几种终止方式 (1)正常退出 从main函数返回[return] 调用exit 调用_exit/_Exit (2)异常退出 调用abort   产生SIGABOUT信号 由信号终止  Ctrl+ ...

  7. exec函数族

    进程程序替换 进程程序替换原理 fork创建子进程执行的是和父进程相同的程序(也有可能是某个分支),通常fork出的子进程是为了完成父进程所分配的任务,所以子进程通常会调用一种exec函数(六种中的任 ...

  8. exec函数族的作用与讲解

    apue看到第八章,对exec函数族的理解一直都很混乱,总觉得不对劲儿,其实不能理解的先暂时跳过,看到后面,再结合实例也就慢慢的理解了. 以下内容转自:http://www.cppblog.com/p ...

  9. 1.2 Linux中的进程 --- fork、vfork、exec函数族、进程退出方式、守护进程等分析

    fork和vfork分析: 在fork还没有实现copy on write之前,Unix设计者很关心fork之后立即执行exec所造成的地址空间浪费,也就是拷贝进程地址空间时的效率问题,所以引入vfo ...

随机推荐

  1. CentOS 7.2:Failed to start IPv4 firewall with iptables

    问题 系统是centos7.2,且已经安装了iptables服务,但是在执行启动命令后,却报了iptables服务无法正常启动的错误. 启动命令如下: systemctl start iptables ...

  2. [UWP 自定义控件]了解模板化控件(8):ItemsControl

    1. 模仿ItemsControl 顾名思义,ItemsControl是展示一组数据的控件,它是UWP UI系统中最重要的控件之一,和展示单一数据的ContentControl构成了UWP UI的绝大 ...

  3. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十五节--缓存小结与ABP框架项目中 Redis Cache的实现

    返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 缓存 为什么要用缓存 为什么要用缓存呢,说缓存之前先说使用缓存的优点. 减少寄宿服务器的往返调用(round-tr ...

  4. Ceph分布式存储-原理介绍及简单部署

    1)Ceph简单概述Ceph是一个分布式存储系统,诞生于2004年,最早致力于开发下一代高性能分布式文件系统的项目.Ceph源码下载:http://ceph.com/download/.随着云计算的发 ...

  5. Docker网络解决方案 - Calico部署记录

    简单来说,实现docker跨主机容器间通信,常用的第三方网络方案是Flannel,Weave,Calico:Flannel会为每个host分配一个subnet,容器从这个subnet中分配ip,这些i ...

  6. 分布式监控系统Zabbix-3.0.3-新版微信报警(企业微信取代企业号)

    一般来说,Zabbix可以通过多种方式把告警信息发送到指定人,常用的有邮件,短信报警方式,但是现在越来越多的企业开始使用zabbix结合微信作为主要的告警方式,这样可以及时有效的把告警信息推送到接收人 ...

  7. jdbcTemplete(转)

    文章来源:http://blog.csdn.net/dyllove98/article/details/7772463 JdbcTemplate主要提供以下五类方法: execute方法:可以用于执行 ...

  8. ABP框架用Dapper实现通过SQL访问数据库

    ABP的框架(2) - 访问数据库   为了防止不提供原网址的转载,特在这里加上原文链接:http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的 ...

  9. 利用ini_set()函数实现对php配置文件的修改

    PHP的配置文件是php.ini,如果要开启或者关闭扩展,还有设置一些模块的相关配置是,就得对该文件进行修改, 修改的方法也很简单,打开php.ini找到对应项直接修改,修改之后需要重新启动才能生效. ...

  10. PDB自动启动以及Oracle Pfile的参数修改示范

    1. Oracle12c 可以使用PDB的模式进行创建, 但是他一般不会自动启动,所以可以穿件一个触发器进行处理 创建语句 CREATE TRIGGER open_all_pdbs AFTER STA ...