exec函数族

exec函数族

fork()函数创建子进程后,子进程往往要调用一种e x e c函数以执行另一个程序。当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其 ma i n函数开始执行。 因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。 有六种不同的e x e c函数可供使用,它们常常被统称为exec函数。

#include<unistd.h>  
int execl(const char *pathname, const char * arg0,.../*(char*)0*/);  
int execv(const char *pathname, char *const argv[]);  
int execle(const char *pathname,const char * arg0,.../*(char*)0,char *const envp[]*/);  
int execve(const char *pathname, char *const argv[],char * const envp[]);  
int execlp(const char *filename, const char * arg0,.../*(char*)0*/);  
int execvp(const char *filename, char *const argv[]);  
//六个函数返回:若出错则为-1,若成功则不返回  

这些函数之间的第一个区别是前四个取路径名作为参数,后两个则取文件名作为参数。当指定filename作为参数时:

如果filename中包含/,则就将其视为路径名。否则就按PAT H环境变量,在有关目录中搜寻可执行文件。

PATH变量包含了一张目录表 (称为路径前缀),目录之间用冒号( : )分隔。例如下列na me = value环境字符串:

PATH = /bin:/usr/bin:/usr/local/bin: 指定在四个目录中进行搜索。(零长前缀也表示当前目录。在value的开始处可用:表示,在行中间则要用::表示,在行尾以:表示。)

如果execlp和execvp中的任意一个使用路径前缀中的一个找到了一个可执行文件,但是该文件不是由连接编辑程序产生的机器可执行代码文件,则就认为该文件是一个 shell脚本,于是 试着调用/bin/sh,并以该filename作为shell的输入。第二个区别与参数表的传递有关 ( l表示表( l i s t ),v表示矢量( v e c t o r ) )。函数execl、execlp和execle要求将新程序的每个命令行参数都说明为一个单独的参数。这种参数表以空指针结尾。

对于另外三个函数( execv, execvp和execve ),则应先构造一个指向各参数的指针数组,然后将该数组地址作为这三个函数的参数。 在使用ANSIC原型之前,对execl , execle和execlp三个函数表示命令行参数的一般方法是: char *arg 0, char *arg 1, ..., char *arg n, (char *) 0 应当特别指出的是:在最后一个命令行参数之后跟了一个空指针。如果用常数 0来表示一个空指针,则必须将它强制转换为一个字符指针,否则它将被解释为整型参数。如果一个整型数的长度与char *的长度不同,exec函数实际参数就将出错。 最后一个区别与向新程序传递环境表相关。以e结尾的两个函数( execle和execve)可以传递一个指向环境字符串指针数组的指针。其他四个函数则使用调用进程中的 environ变量为新程序复制现存的环境。通常,一个进程允许将其环境传播给其子进程,但有时也有这种情况,进程想要为子进程指定一个确定的环境。

例如,在初始化一个新登录的 shell时,login程序创建一个只定义少数几个变量的特殊环境,而在我们登录时,可以通过 shell启动文件,将其他变量加到环境中。

在使用 ANSI C原型之前, execle 的参数是:char * pathname, char *arg 0, ⋯, char *a rg n, (char *)0, char *envp[ ] 从中可见,最后一个参数是指向环境字符串的各字符指针构成的数组的指针。而在 ANSIC原型中,所有命令行参数,包括空指针,e n v p指针都用省略号(⋯)表示。 这六个e x e c函数的参数很难记忆。函数名中的字符会给我们一些帮助。字母 p表示该函数

取filename作为参数,并且用PATH环境变量寻找可执行文件。字母l表示该函数取一个参数表,它与字母v互斥。v表示该函数取一个arg v[ ]。最后,字母e表示该函数取e nvp[ ]数组,而不使用当前环境

这六个函数中只有一个execve是内核的系统调用。另外五个只是库函数,它们最终都要调用系统调用。这六个函数之间的关系示于图8 - 2中。在这种安排中,库函数 execlp 和execvp 使用PATH环境变量查找第一个包含名为filename的可执行文件的路径名前缀。

例1:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 
 5 int main(int argc,char * argv[])
 6 {
 7     if(argc<2)
 8     {
 9         perror("you haven't input the filename,please try again!
");
10         exit(EXIT_FAILURE);
11     }
12     if(execl("./create_file","create_file",argv[1],NULL)<0)
13         perror("execl error");
14 }

可以看见的是有一个名为create_file的可执行文件用于创建文件。在这里我们使用execl函数替换程序。

 

例2:

代码:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<unistd.h>
 4 
 5 int main(int argc,char * argv[])
 6 {
 7         if(argc<2)
 8         {
 9                 perror("you haven't input the filename,please try again!
");
10                 exit(EXIT_FAILURE);
11         }
12         if(execl("/bin/touch","touch",argv[1],NULL)<0)
13                 perror("execl error");
14 }                                                                

可以看见我们将exec2 成功的替换为了touch。并成功的执行了。

 

参考资料

Linux/Unix系统编程手册

Unix环境高级编程

Linux程序设计

原文地址:https://www.cnblogs.com/mumu597/p/12897935.html