目录
exec函数族提供了一种从一个进程中启动另一个程序的方法。
exec函数族是unix系统提供的六个命令行函数,需要链接到<unistd.h>头文件
exec的特点是每一个函数的第一个参数就是可执行的二进制文件或者可执行的脚本文件,当前进程如果调用了exec函数族中的其中一个函数,然后会调用某进程,从而将当前进程的除进程号之外的所有资源都占用,相当于原进程结束,或者说原进程结束了任务不能再为当前系统作出贡献,然后调用exec函数让这个进程焕发新机,继续为当前系统作出贡献。exec函数族六大函数的参数除路径和环境变量和NULL外,其余都是命令行参数。
exec函数族共六个函数,这6个函数分为两个系列,分别为execl系列和execv系列。
一、exec的六大函数:
execl系列:
int execl(const char * path,const char * arg,… ,NULL);
int execle(const char * path,const char * arg,char * const envp[],,NULL);
int execlp(const char * file,const char * arg,…,NULL);
execv系列:
int execv(const char * path,char * const argv[],NULL);
int execve(const char * path,char * const argv[],char * const envp[],NULL);
int execvp(const char * file,char * const argv[],NULL);
execl系列函数和execv系列函数的区别在于 l 和 v
l是list(列表)的意思,在exec函数族中有 l 表示该函数以函数的参数形式,一个一个的输入。
v是vector(矢量)的意思,在exec函数族中有 v 表示该函数以指针数组的方式传入参数。
e(environment)表示从环境变量中获取变量(数据),p(path)表示从指定的路径中获取变量(数据)。
path可以是绝对路径或者相对路径,arg表示第零个参数,envp[]参数是带有 e 的exec函数族具有的,表示可以指定一个环境变量数组,argv[]是带v的exec函数族具有的,表示所有的命令行参数可以打包成数组然后数组作为参数传入函数。
exec函数族的六个函数的返回值都一样,调用失败返回-1.调用成功则什么都不返回。
注意:exec族的六个函数的最后一个参数必须是NULL,表明命令行参数没有了,可以结束。
1 execl
1.0 execl案例1:
execl案例1:通过execl二进制文件执行a二进制文件
int execl(const char * path,const char * arg,… ,NULL);
a.c
#include<stdio.h>
int main(int argc,char *argv[])
{
printf("hello world\n");
while(*argv!=NULL)
{
printf("%s\n",*argv++);
}
return 0;
}
execl.c
#include<stdio.h>
#include<unistd.h>
int main()
{
//int execl(const char * path,const char * arg,… ,NULL);
//execl案例
execl("/home/exec_cluster/a","我是execl函数,我执行后下面的函数不再执行","第一个参数(./a是第零个参数)","第二个参数","...",NULL);
printf("This is an execl function\n");
return 0;
}
输出结果: execl文件的printf函数未打印(侧证明execl函数调用后,当前进程就不再执行,由第一个参数的进程来执行)
execl案例2:通过execl二进制文件执行 ls 系统命令
int execl(const char * path,const char * arg,… ,NULL);
1.1 execl案例2:
#include<stdio.h>
#include<unistd.h>
int main()
{
// int execl(const char * path,const char * arg,… ,NULL);
//execl案例
execl("/usr/bin/ls","-a","-l","-h",NULL);
printf("This is an execl function\n");
return 0;
}
2 execle
execle案例1:
int execle(const char * path,const char * arg,char * const envp[],,NULL);
2.0 execle案例1:
#include<stdio.h>
#include<unistd.h>
int main()
{
// int execle(const char * path,const char * arg,char * const envp[],,NULL);
//execle案例
char *envp[]={"PATH=/usr/bin",NULL};
execle("/usr/bin/ls","ls","-l","-a",NULL,envp);
printf("This is an execl function\n");
//该程序将调用execle函数,执行/bin/ls命令,并将其输出结果重定向到标准输出。在调用execle函数时,我们指定了命令路径,命令名称和参数以及环境变量。由于我们指定了环境变量,因此/bin/ls将在指定的环境下执行。
return 0;
}
输出结果:
execle案例2:
int execle(const char * path,const char * arg,char * const envp[],,NULL);
2.1 execle案例2:
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
// int execle(const char * path,const char * arg,char * const envp[],,NULL);
//execle案例
char *envp[]={"PATH=/usr/bin","USER=root",NULL};
execle("/usr/bin/env","env",NULL,envp);
printf("This is an execle function\n");
//该程序将调用execle函数,执行/bin/ls命令,并将其输出结果重定向到标准输出。在调用execle函数时,我们指定了命令路径,命令名称和参数以及环境变量。由于我们指定了环境变量,因此/bin/ls将在指定的环境下执行。
return 0;
}
输出结果:
3 execlp
execlp案例:
int execlp(const char * file,const char * arg,…,NULL);
3.0 execlp案例1:
execlp.c
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
// int execlp(const char * file,const char * arg,…,NULL);
//execlp案例
execlp("ls","-a","-l","-h",NULL);
printf("This is an execlp function\n");
//该程序将调用execlp函数,执行ls命令,并将其输出结果重定向到标准输出。在调用execlp函数时,我们指定了命令名称和参数,但没有指定命令路径。因此,系统将在环境变量PATH中查找命令。
return 0;
}
输出结果:
3.1 execlp案例2:
execlp.c
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
// int execlp(const char * file,const char * arg,…,NULL);
//execlp案例
execlp("echo","echo","Dragon Boat Festival Health",NULL);
printf("This is an execlp function\n");
//该程序将调用execlp函数,执行ls命令,并将其输出结果重定向到标准输出。在调用execlp函数时,我们指定了命令名称和参数,但没有指定命令路径。因此,系统将在环境变量PATH中查找命令。
return 0;
}
输出结果:
4 execv
execv案例:
int execv(const char * path,char * const argv[],NULL);
4.0 execv案例1:
execv.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execv案例:
// int execv(const char * path,char * const argv[],NULL);
char *argv[]={"ls","-a","-l","-h",NULL};
execv("/bin/ls",argv);
printf("This is an execv function\n");
//execv函数有别于execl,他可以将所有的命令行参数存放到一个指针数组中,然后指针数组作为execv函数参数
// 该程序将调用execv函数,执行/bin/ls命令,并将其输出结果重定向到标准输出。在调用execv函数时,我们指定了命令路径和参数
return 0;
}
输出结果:
4.1 execv案例2:
execv.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execv案例:
// int execv(const char * path,char * const argv[],NULL);
char *argv[]={"echo","Dragon Boat Festival Health",NULL};
execv("/usr/bin/echo",argv);
printf("This is an execv function\n");
//execv函数有别于execl,他可以将所有的命令行参数存放到一个指针数组中,然后指针数组作为execv函数参数
// 该程序将调用execv函数,执行/bin/ls命令,并将其输出结果重定向到标准输出。在调用execv函数时,我们指定了命令路径和参数
return 0;
}
result:
5 execve
execve案例:
int execve(const char * path,char * const argv[],char * const envp[],NULL);
5.0 execve案例1:
execve.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execve案例:
// int execve(const char * path,char * const argv[],char * const envp[],NULL);
char *argv[]={"ls","-l","-a","-h",NULL};
char *envp[]={"PATH=/usr/bin",NULL};
execve("/bin/ls",argv,envp);
printf("This is an execve function\n");
//定义了两个指针数组,分别是命令行指针数组和环境变量指针数组
return 0;
}
Result:
5.1 execve案例2:
execve.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execve案例:
// int execve(const char * path,char * const argv[],char * const envp[],NULL);
char *argv[]={"echo","Happy birthday to you",NULL};
char *envp[]={"PATH=/usr/bin",NULL};
execve("/bin/echo",argv,envp);
printf("This is an execve function\n");
//定义了两个指针数组,分别是命令行指针数组和环境变量指针数组
return 0;
}
Result:
6 execvp
execvp案例:
int execvp(const char * file,char * const argv[],NULL);
6.0 execvp案例1:
execvp.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execvp案例:
// int execvp(const char * file,char * const argv[],NULL);
char *argv[]={"ls","-l","-a","-h",NULL};
execvp("/usr/bin/ls",argv);
printf("This is an execvp function\n");
//该程序将调用execvp函数,执行ls命令,并将其输出结果重定向到标准输出。在调用execvp函数时,我们指定了命令名称和参数,但没有指定命令路径。因此,系统将在环境变量PATH中查找命令。
return 0;
}
Result:
6.1 execvp案例2:
execvp.c
#include<stdio.h>
#include<unistd.h>
int main()
{
// execvp案例:
// int execvp(const char * file,char * const argv[],NULL);
char *argv[]={"echo","hello","world",NULL};
execvp("echo",argv);
printf("This is an execvp function\n");
//该程序将调用execvp函数,执行ls命令,并将其输出结果重定向到标准输出。在调用execvp函数时,我们指定了命令名称和参数,但没有指定命令路径。因此,系统将在环境变量PATH中查找命令。
return 0;
}
Result:
二、总结
exec函数族是基于unix/linux内核的,需要包含头文件<unistd.h>链接使用,分为两大系列,execl系列和execv系列,execl系列所有的命令行参数需要都输入到函数中,而execv系列通过定义指针数组来保存所有的命令行参数,然后将指针数组作为函数的参数输入。因此execl系列适用于参数不多的场景,也就是说如果函数的命令行参数过多,execl系列会使得函数的参数太多,使得代码难看,容易分不清这个函数,因此大多数情况还是使用execv系列较好,这样代码好看点。