作用:当我们使用 fork 函数创建一个新的子进程后,子进程往往需要调用一种 exec 函数去执行另一个程序。当进程调用一种 exec 函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。
注意:调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。
exec函数共七种可供使用,(有了这些exec函数使得UNIX系统进程控制原语更加完善):
#include
int execl(const char *path, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
返回值:exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
参数说明: path:可执行文件的路径名字 arg:可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束 file:如果参数file中包含/,则就将其视为路径名,否则就按 PATH环境变量,在它所指定的各目录中搜寻可执行文件。
异同点:一、前三个函数取路径名作为参数,后三个函数取文件名作为参数,最后一个则取文件描述符作为参数。
1、如果file中包含 /,则就其视为路径名;否则就按照PATH环境变量,在它所指的各目录中搜寻可执行文件。
二、关于参数(l 表示列表list ,v表示矢量vector)。函数execl、execlp和execle 要求新程序的每个命令行参数都作为一个单独的参数。这种参数表以空指针(NULL)结尾。对于另外的函数则应先构造一个指向各参数的指针数组,然后将该数组的地址作为这4个函数的参数。(注:如果使用常量0来表示一个空指针,则必须强制转换成一个指针;否则将被解释为整型参数。)
exec函数的参数很难记忆。函数名中包含的字符会给我们一些帮助。
字母 p:表示该函数取filename作为参数,并且用PATH环境变量寻找可执行的文件。
字母 l:表示该函数取一个参数表,它与字母v互斥。
字母v:表示该函数取一个argv [ ]矢量。
字母 e: 表示该函数取 envp [ ]数组,而不使用当前环境。
/argecho.c //被调用函数
#include
int main(int argc, char** argv)
{
int i;
for(i=0;i printf("argv[%d] : %s\n",i,argv[i]); } return 0; } execl函数的实现: #include #include int main() { printf("before execl:\n"); if(execl("./argecho","file1","file2",NULL) == -1){ printf("execl failed\n"); perror("execl:\n"); } printf("after execl\n"); return 0; } 运行结果: 通过结果: 1、exec函数在成功运行后,新程序将完全替换原函数,原函数剩下的部分将不会运行。 2、exec函数在出错时会返回-1,并且设置errno。因此,可以调用perror函数对出错原因进行分析。 exec可以调用可执行程序,同样的也可以执行ls 、pwd 这样的指令。 通过调用whereis指令,寻找 date 指令的绝对路径: #include #include int main() { printf("before execl:\n"); if(execl("/bin/date","date",NULL) == -1){ printf("execl failed\n"); perror("execl:\n"); } printf("after execl\n"); return 0; } 上述步骤中,需要调用 whereis 找到绝对路径后,才可在指定路径下调用新程序。若没有绝对路径,则会显示errno。 execlp函数的实现: #include #include int main() { printf("before execl:\n"); if(execlp("date","date",NULL) == -1){ printf("execl failed\n"); perror("execl:\n"); } printf("after execl\n"); return 0; } 上述实验下,execlp函数带p,所以能通过环境变量PATH查找到可执行文件date。 execvp函数的实现: 带v与带l的属于互斥关系,两者的不同在于参数的表现形式。(带v 的函数应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。) include #include int main() { printf("before execl:\n"); char* argv[] = {"date",NULL}; if(execvp("date",argv) == -1){ printf("execl failed\n"); perror("execl:\n"); } printf("after execl\n"); return 0; } execle函数的使用: #include int main(int argc,char** argv) { int i; char **ptr; extern char **environ; for(i=0;i printf("argv[%d]:%s\n",i,argv[i]); } for(ptr = environ;*ptr != 0;ptr++){ printf("%s\n",*ptr); } return 0; } #include #include int main() { char *init_env[] = {"USER=unknown","PATH=/tmp",NULL}; pid_t pid; if((pid = fork()) < 0){ printf("fork error\n"); }else if(pid == 0){ printf("before execle\n"); if(execle("./echoall","echoall","myargl","MY ARG2",NULL,init_env) < 0){ perror("execle\n"); } printf("after execle\n"); } waitpid(pid,NULL,0); return 0; } 结果: 带有e的函数可以传递一个指向环境字符串指针数组的指针,通过这个地址可以改变新函数的环境变量。 总结:exec族函数的作用大体相同,区别在于所带参数的表现形式的不同,以及配置的功能些许不同。 Linux---关于环境变量(如何配置环境变量) 1、如何查找当前环境变量? 2、如何配置环境变量? 例子:如需要将以下路径添加至环境变量 输入:export PATH=$PATH:需要添加的路径 随后再次输入echo $PATH,新的路径便添加进来了。 这样就可以在运行不在当前路径下,但是在环境变量当中的可执行文件了。 文章链接
发表评论