Linux下exec函数族详解

筅森魡賤 提交于 2020-02-28 04:50:32

 

       对于exec函数族来说,它的作用通俗来说就是使另一个可执行程序替换当前的进程,当我们在执行一个进程的过程中,通过exec函数使得另一个可执行程序A的数据段、代码段和堆栈段取代当前进程B的数据段、代码段和堆栈段,那么当前的进程就开始执行A中的内容,这一过程中不会创建新的进程,而且PID也没有改变。

一般exec函数族的用途有以下两种:

       1. 当进程不需要再往下继续运行时,调用exec函数族中的函数让自己得以延续下去。

       2. 如果当一个进程想执行另一个可执行程序时,可以使用fork函数先创建一个子进程,然后通过子进程来调用exec函数从而实             现可执行程序的功能。

通过man命令来看一下exec函数族:

       首先exec并不是一个函数名,之所以叫函数族就说明它有很多个不同的函数,但是这些函数的功能是一样的,只不过参数不同使用的方式也略不相同。那么在man命令下看到的exec函数原型是这样的:

       #include <unistd.h>

       extern char **environ;

       int execl(const char *path, const char *arg, .../* (char  *) NULL */);
       int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
       int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],char *const envp[]);

       它们都是以exec为前缀,那么不同的之后后面的一些字符,l表示命令行参数列表、p表示PATH环境变量、v表示使用参数数组、e使用环境变量数组。其中execvpe和execle一般不常用,下面就以例子来看看具体的用法以及所展示出来的效果是怎么样的,便于更好的理解exec函数的作用,先来看一下下面的这个代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        execl("/bin/ls", "ls", "-l", NULL);
        perror("execl");
        exit(1);
}

       这个程序很简单,就是用当前的进程调用ls这个可执行程序,并添加了-l参数。由于execl成功调用后这个进程的代码段都被替换了,自然下面的代码就不会再执行了,所以也就没有返回值了,但是当调用失败后就会返回-1并设置errno值。那么在成功调用后实际上这个进程就变成了ls,然后执行ls -l的命令,因为我们用的是execl函数,所以第一个参数就需要用ls的所在目录,第二个参数其实没有实际意义,因为已经指定了ls的所在位置,所以第二个参数随便设置就可以但是不可以没有,第三个参数就是你所需要的功能,这里我用-l来举例,最后用NULL表示结束。那么运行结果如下:

total 16
-rw-r--r-- 1 charles charles  163 Feb 27 15:49 a.c
-rwxr-xr-x 1 charles charles 8384 Feb 27 15:49 test

       如果是用execlp,那么第一个参数就可以不用加ls的路径了,直接是ls就可以了,因为系统会去PATH中查找。如果是execv的话,后面的参数就要是一个指针数组的形式,可以看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
        char *argv[] = {"ls", "-l", NULL};
        execv("/bin/ls", argv);
        perror("execl");
        exit(1);
}

一般的exec函数族的错误原因:

1. 找不到文件或者路径,此时errno为ENOENT。

2. 数组argv和envp(环境变量数组)没有以NULL结尾,此时errno为EFAULT。

3. 没有对应可执行文件的运行权限,此时errno为EACCES。

 

       下面用exec函数来实现一个简单的程序b,我们先写一个这样的程序,getchar获取输入的小写字母,然后将其转换成大写输出出来,代码如下:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
	char s;
	while((s = getchar())!=EOF){
		putchar(toupper(s));
	}
	return 0;
}

      然后我们再写一个程序a,它的作用是将一个文件打开,然后读取文件中的内容,然后调用exec函数打开这个转换大写字母的程序并将原文件中的内容输出。这里这个程序用到了dup2函数来进行重定向,直接看代码吧,不难理解。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	if(argc != 2){                     // 接收到两个参数
		printf("Open error!\n");
		exit(1);
	}
	int fd = open(argv[1], O_RDONLY);  // 以只读的方式打开文本文件
	if(fd < 0){
		perror("open file");
		exit(1);
	}
	dup2(fd, STDIN_FILENO);            // 输入重定向,使STDIN_FILENO指向fd所指的文件
	close(fd);
    execv("./upper", "upper", NULL);   // 调用upper可执行文件
	perror("execl");
	exit(1);
}

       首先我们编译第一个程序生成可执行程序upper,然后再创建一个文本文件text,里面内容为helloworld,然后我们运行程序a,得到下面的运行结果:

                                        

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!