exec函数族的使用
作者:王姗姗,华清远见嵌入式学院讲师。
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函数族的使用的更多相关文章
- exec函数族实例解析
exec函数族实例解析 fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的 ...
- exec函数族,守护进程,线程同步和互斥
2015.3.2 进程和程序有三点不同:1,存在位置不同,程序:硬盘,磁盘.进程:内存2. 程序是静态的,进程是动态的 执行./a.out -->bash->bash程序调用fork()- ...
- linux exec函数族
1.简介 在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是: #include <unistd.h> extern char **environ; ...
- Linux进程控制——exec函数族
原文:http://www.cnblogs.com/hnrainll/archive/2011/07/23/2114854.html 1.简介 在Linux中,并不存在exec()函数,exec指的是 ...
- Linux 环境下 fork 函数和 exec 函数族的使用
前言 接触 Linux 已经有几个月了,以前在网上看各路大神均表示 Windows 是最烂的开发平台,我总是不以为然,但是经过这段时间琢磨,确实觉得 Linux 开发给我带来不少的便利.下面总结一下学 ...
- Linux进程实践(3) --进程终止与exec函数族
进程的几种终止方式 (1)正常退出 从main函数返回[return] 调用exit 调用_exit/_Exit (2)异常退出 调用abort 产生SIGABOUT信号 由信号终止 Ctrl+ ...
- exec函数族
进程程序替换 进程程序替换原理 fork创建子进程执行的是和父进程相同的程序(也有可能是某个分支),通常fork出的子进程是为了完成父进程所分配的任务,所以子进程通常会调用一种exec函数(六种中的任 ...
- exec函数族的作用与讲解
apue看到第八章,对exec函数族的理解一直都很混乱,总觉得不对劲儿,其实不能理解的先暂时跳过,看到后面,再结合实例也就慢慢的理解了. 以下内容转自:http://www.cppblog.com/p ...
- 1.2 Linux中的进程 --- fork、vfork、exec函数族、进程退出方式、守护进程等分析
fork和vfork分析: 在fork还没有实现copy on write之前,Unix设计者很关心fork之后立即执行exec所造成的地址空间浪费,也就是拷贝进程地址空间时的效率问题,所以引入vfo ...
随机推荐
- 总目录(Catalog)
总目录(Catalog) C#高级编程(C# advanced programming) 1.并发编程(Concurrent programming)(8) ...... 数据结构与算法(Data s ...
- 编写自己的dapper lambda扩展-使用篇
前言 这是针对dapper的一个扩展,支持lambda表达式的写法,链式风格让开发者使用起来更加优雅.直观.现在暂时只有MsSql的扩展,也没有实现事务的写法,将会在后续的版本补充. 这是个人业余的开 ...
- 没有 iOS 开发者账号的情况下部署到真机的方法
原文发表于我的技术博客 本文分享了官方推荐的没有 iOS 开发者账号的情况下部署到真机的方法,供参考. 原文发表于我的技术博客 1. 官方推荐的方法 原文在此,也就是 Ionic 官方团队在博客中分享 ...
- git bash返回上一级目录
YITU-LIUMZ+Administrator@yitu-liumz MINGW64 ~/learngit/gitskills (dev)$ cd ..\ 注意 cd 后面有空格 然后就会弹出一个 ...
- 分布式监控系统Zabbix3.4-钉钉告警配置记录
群机器人是钉钉群的高级扩展功能,群机器人可以将第三方服务的信息聚合到群聊中,实现自动化的信息同步.例如:通过聚合GitHub,GitLab等源码管理服务,实现源码更新同步:通过聚合Trello,JIR ...
- Centos下PPTP环境部署记录
PPTP(点到点隧道协议)是一种用于让远程用户拨号连接到本地的ISP,通过因特网安全远程访问公司资源的新型技术.它能将PPP(点到点协议)帧封装成IP数据包,以便能够在基于IP的互联网上进行传输.PP ...
- 《Linux内核设计与实现》读书笔记六
第4章 进程调度35 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有通过调度程序的合理调度,系统资源才能最 ...
- win10装MySQL5.7
越来越发现装MySQL很费劲啊,装了N次,都很懵逼,找对的解决方案很重要. Mysql5.7下载地址:http://xiazai.zol.com.cn/detail/4/33431.shtml 安装步 ...
- GitHub18
兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...
- 牛客OI周赛7-普及组
https://ac.nowcoder.com/acm/contest/372#question A.救救猫咪 #include <bits/stdc++.h> using namespa ...