前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux下exec函数族详解

Linux下exec函数族详解

作者头像
Ch_Zaqdt
发布2020-03-02 11:12:19
8.1K0
发布2020-03-02 11:12:19
举报
文章被收录于专栏:Zaqdt_ACMZaqdt_ACM

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

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

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

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

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

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

代码语言:javascript
复制
       #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函数的作用,先来看一下下面的这个代码:

代码语言:javascript
复制
#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表示结束。那么运行结果如下:

代码语言:javascript
复制
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的话,后面的参数就要是一个指针数组的形式,可以看下面的代码:

代码语言:javascript
复制
#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获取输入的小写字母,然后将其转换成大写输出出来,代码如下:

代码语言:javascript
复制
#include <stdio.h>
#include <ctype.h>

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

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

代码语言:javascript
复制
#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,得到下面的运行结果:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档