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

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. React 等框架使用 index 做 key 的问题

    React 等框架使用 index 做 key 的问题 假如有两个树,一个是之前,一个是更变之后,我们抽象成两种可能性. 插入内容在最后 插入内容在最前 关于插在中间,原理一样,就不阐述. 使用 ul ...

  2. iOS开发简记(3):tips提示

    我有一个需求:在点击或长按某个按钮时,需要显示提示,包括简单的文字提示,还有复杂一点的图片甚至是动态图的提示(可能还要加上文字). (1)文字tips 使用之前介绍的qmuikit里面的QMUITip ...

  3. SQL行转列汇总 (转)

    PIVOT 用于将列值旋转为列名(即行转列),在 SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT 的一般语法是:PIVOT(聚合函数(列) FOR 列 in (…) )A ...

  4. Name方法

    重命名磁盘文件.目录或文件夹. 语法 Name 旧路径名称 As 新路径名称 “Name”**** 语句语法包含以下部分: 部分 说明 旧路径名称 必需. 字符串表达式,指定现有的文件名和位置;可能包 ...

  5. Nginx负载均衡中后端节点服务器健康检查的操作梳理

    正常情况下,nginx做反向代理,如果后端节点服务器宕掉的话,nginx默认是不能把这台realserver踢出upstream负载集群的,所以还会有请求转发到后端的这台realserver上面,这样 ...

  6. 【CV】ICCV2015_Learning Temporal Embeddings for Complex Video Analysis

    Learning Temporal Embeddings for Complex Video Analysis Note here: it's a review note on novel work ...

  7. 数学建模-lingo使用

    1.安装启动,软件下载地址:http://pc.xzstatic.com/2017/06/LINGO14 .zip.此为免安装版,打开后双击Lingo11.exe即可启动软件. 2.示例:某商品单位成 ...

  8. atcoder A - Frog 1(DP)

    A - Frog 1 Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement There a ...

  9. shell脚本--shift参数左移

    参数左移什么意思呢?这个参数指的是在运行脚本时,跟在脚本名后面的参数,前面已经讲过,可以使用$#来获取参数的个数,使用$*来获取所有的参数,而参数左移的含义是这样的:有个指针指向参数列表第一个参数,左 ...

  10. HDU 1236 排名(Microsoft_zzt)

    http://acm.hdu.edu.cn/showproblem.php?pid=1236 Problem Description 今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完 ...