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 ...
随机推荐
- FreeRTOS 任务与调度器(2)
在上一篇我们介绍了FreeRTOS任务的一些基本操作和功能,今天我们会介绍一个很好很强大的功能——任务通知 任务通知可以在不同任务之间传递信息,它可以取代二值信号量.计数信号量.事件标志组.深度为1的 ...
- Bash Shebang 小结
在 shell(Bash 是一种 shell) 中执行外部程序和脚本时,Linux 内核会启动一个新的进程,以便在新的进程中执行指定的程序或脚本.内核知道该如何为编译型的程序做这件事,但是对于脚本程序 ...
- Centos7下关于系统用户密码规则-运维笔记
针对Centos7下的系统用户的密码规则复杂度的设置,处于安全考虑,说明如下: 一.设置密码规则 1)密码长度.有效期 /etc/login.defs文件是当创建用户时的一些规划,比如创建用户时,是否 ...
- 个人博客作业_week7
心得 在为期将近一个月的团队编程中,给我感受最深的是敏捷开发和团队中队员之间的互补. 在最初的软件开发中,由于以前没有这方面的经验,所以并没有很大的进展.在慢慢过度中,我们找到了自己的节奏感,大家各自 ...
- Bing词典分析
0x01 Bug测试结果 本次测试的是Bing词典wp版本V4.5.2,经过测试,共发现如下Bug. 1.更新后,旧版本首页的每日单词与文章推荐不能重新获得,部分搜索历史记录丢失. 2.在单词挑战模式 ...
- Android动画总结
本文总结常用属性方法等,详细学习可使用如下郭霖大神文章: Android属性动画完全解析(上),初识属性动画的基本用法 Android属性动画完全解析(中),ValueAnimator和ObjectA ...
- PAT L3-008 喊山
https://pintia.cn/problem-sets/994805046380707840/problems/994805050709229568 喊山,是人双手围在嘴边成喇叭状,对着远方高山 ...
- 使用非服务器磁盘(MBROnly)安装ESXi时的方法.
From ESXi 5.0, if you install ESXi to a empty hard disk, the target disk will be prepared with GPT-b ...
- 转《ionic生命周期》
1.认识ionic的生命周期钩子 截至ionic 3.8.0版本,框架提供了8个钩子函数,它们分别会在页面生命周期的各个阶段被触发,我们来简单了解一下. 1.1 ionViewDidLoad 页面加载 ...
- vue render function & dataset
vue render function & dataset https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In ...