为什么要用exec族函数,有什么用
有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
在Linux中使用exec函数族主要有以下两种情况
- 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec 函数族让自己重生。
- 如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。
实际上,在Linux中并没有exec函数,而是有6个以exec开头的函数族
#include
int execl(const char *path, const char *arg, …)
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg, …, char *const envp[])
int execve(const char *path, char *const argv[], char *const envp[])
int execlp(const char *file, const char *arg, …)
int execvp(const char *file, char *const argv[])
参数介绍:
path:指定程序的具体路径及程序名字
arg :传入给程序的参数,最后参数必须为NULL;(NULL作为参数列表的结束标记)
file:命令名
envp:环境变量参数
exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
l : 使用参数列表
p:使用文件名,并从PATH环境进行寻找可执行文件
v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
返回值:
exec函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
示例代码:
说明:因为是笔记,就简写了,只写了execl.execlp.execv,execvp。
//execl #include#include #include int main(void) { printf("before execln"); if(execl("/bin/ls","ls","-l",NULL) == -1) // if(execl("/bin/date","date",NULL,NULL) == -1) { printf("execl failed!n"); perror("why"); } printf("after execln"); return 0; }
//execlp #include#include #include int main(void) { printf("before execln"); if(execlp("ps","ps",NULL) == -1) { printf("execl failed!n"); perror("why"); } printf("after execln"); return 0; }
//execv #include#include #include int main(void) { printf("before execln"); char *argv[] = {"/ps",NULL,NULL}; if(execv("/bin/ps",argv) == -1) { printf("execl failed!n"); perror("why"); } printf("after execln"); return 0; }
//execvp #includeexecl配合fork#include #include int main(void) { printf("before execln"); char *argv[] = {"ps",NULL,NULL}; if(execvp("ps",argv) == -1) { printf("execl failed!n"); perror("why"); } printf("after execln"); return 0; }
#include二.system函数 函数原型#include int main() { pid_t pid; int data; while(1){ printf("please input a data:n"); scanf("%d",&data); if(data == 1){ pid = fork();//创建进程 if(pid > 0){ wait(NULL); }else if(pid == 0){ execl("./textConfig","textConfig","text.config",NULL); } } } return 0; }
NAME
system - execute a shell command
SYNOPSIS
#includeint system(const char *command);
返回值
如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。如果 system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
#include三.popen函数 函数原型#include #include int main(void) { printf("before execln"); if(system("ps") == -1) { printf("execl failed!n"); } printf("after execln"); return 0; }
NAME
popen, pclose - pipe stream to or from a process
SYNOPSIS
#include
FILE *popen(const char *command, const char *type); int pclose(FILE *stream);
比system的好处:可以获取运行结果。
参数说明:
command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。
mode: 只能是读或者写中的一种,得到的返回值(标准 I/O 流)也具有和 type 相应的只读或只写类型。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。
返回值:
如果调用成功,则返回一个读或者打开文件的指针,如果失败,返回NULL,具体错误要根据errno判断
int pclose (FILE* stream)
参数说明:
stream:popen返回的文件指针
返回值:
如果调用失败,返回 -1
作用:
popen() 函数用于创建一个管道:其内部实现为调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程这个进程必须由 pclose() 函数关闭。
#include#include #include int main(void) { char ret[1024] = {0}; FILE *fp; fp = popen("ps","r"); int n_read = fread(ret,1,1024,fp); printf("reat ret %d byte,ret = %sn",n_read,ret); return 0; }
运行结果:



