目录
- exec()函数族-基础概念
- exec()函数族参数分析—很重要
- 关于fork()的第二种常见用法
- 案例,在fork子进程调用exec函数族
exec()函数族-基础概念----man 3 exec
作用:execute a file,执行指定路径下的可执行文件
成员:execl(); execlp(); execle(); execv(); execvp(); execvpe()–不用了;
经常使用的是execve():
注:只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数
//参数是列表
execl(): arg0, arg1, ..., argn.
int execl(const char *path, const char *arg, ...);
execlp():
int execlp(const char *file, const char *arg, ...);
execle():
int execle(const char *path, const char *arg,..., char * const envp[]);
//参数是数组
execv():
int execv(const char *path, char *const argv[]);
execvp():
int execvp(const char *file, char *const argv[]);
execvpe():好像弃用了,资料少。。
int execvpe(const char *path, char *const argv[], char * const envp[]);
execve():
int execve(const char *filename, char *const argv[],char *const envp[]);
举个例子:
exec()函数族参数分析—很重要
(1):“l”和“v”表示参数是以列表还是以数组的方式提供,但是都要以NULL结尾,arg[0]:需要执行二进制程序的名字
(2):“p”表示这个函数的第一个参数是*path,就是以绝对路径来提供程序的
路径,也可以以当前目录作为目标
(3):“e”表示为程序提供新的环境变量,不需要给NULL
(4):所有参数要求全部来自man文档,请仔细阅读,如果出现错误或字符参数警告,你可以再仔细分析下这6个函数。
给一张简单直观图:
小案例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/****************************************************************************************
** exec函数族
//参数是列表
** execl(): arg0, arg1, ..., argn.
** int execl(const char *path, const char *arg, ...);
** execlp():
** int execlp(const char *file, const char *arg, ...);
** execle():
** int execle(const char *path, const char *arg,..., char * const envp[]);
//参数是数组
** execv():
** int execv(const char *path, char *const argv[]);
** execvp():
** int execvp(const char *file, char *const argv[]);
** execvpe():
** int execvpe(const char *path, char *const argv[], char * const envp[]);
**注意:execvpe要#ifdef __USE_GNU支持
execl,execlp,execle:
The first argument, by convention, should point to the filename associated with the file being executed,即arg0是可执行程序名字
null-terminated strings(空终止字符串):The list of arguments must be terminated by a NULL pointer(结尾一定要是NULL)
execv,execvp,execvpe:
也必须满足上述两个要求,且以数组传入
p:绝对路径来提供程序的路径
e:表示为程序提供新的环境变量 extern char **environ;
** RETURN VALUE
** The exec() functions only return if an error has have occurred. The return value is -1
****************************************************************************************/
int main()
{
if((execl("/linuxsystemcode/systemcode/pid/helloexecl","helloexecl","execl")) == -1) //存在就调用helloexecl应用程序,不会再返回来了
{
perror("execl");
exit(1);
}
printf("execl error!!!\n"); //正常情况下,是不会执行的
return 0;
}
helloexecl.c
//helloexecl.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 10;
while(i--)
{
printf("%s %d.\n",argv[1], i);
}
}
输出:
关于fork()的第二种常见用法
下面是程序框架:并发执行,谁先谁后执行完,并不清楚。父进程,子进程结束时间先后,会使输出不可控,你要在代码里更正
案例,在fork子进程调用exec函数族
下面的代码结合fork和6个exec族内函数的例子:
#include <stdio.h>
#include <unistd.h>
//#define _GNU_SOURCE //execvpe才需要
//extern char **environ; //新环境变量,下面全给NULL
/****************************************************************************************
** exec函数族与fork
//参数是列表
** execl(): arg0, arg1, ..., argn.
** int execl(const char *path, const char *arg, ...);
** execlp():
** int execlp(const char *file, const char *arg, ...);
** execle():
** int execle(const char *path, const char *arg,..., char * const envp[]);
//参数是数组
** execv():
** int execv(const char *path, char *const argv[]);
** execvp():
** int execvp(const char *file, char *const argv[]);
** execvpe():好像弃用了,资料少。。
** int execvpe(const char *path, char *const argv[], char * const envp[]);
** execve():
** int execve(const char *filename, char *const argv[],char *const envp[]);
**注意:execvpe要#ifdef __USE_GNU支持
execl,execlp,execle:
The first argument, by convention, should point to the filename associated with the file being executed,即arg0是可执行程序名字
null-terminated strings(空终止字符串):The list of arguments must be terminated by a NULL pointer(结尾一定要是NULL)
execv,execvp,execvpe:
也必须满足上述两个要求,且以数组传入
p:绝对路径来提供程序的路径
e:表示为程序提供新的环境变量 extern char **environ;
** RETURN VALUE
** The exec() functions only return if an error has have occurred. The return value is -1
****************************************************************************************/
int main(void)
{
char *arg[]={"ls","-i",NULL}; //参数数组
//子进程1--int execl(const char *path, const char *arg, ...);
if(fork() == 0) //子进程调用exe函数族
{
printf("Forks 1 is Ok!!! : execl\n");
if(execl("/bin/ls","ls","-i",NULL) == -1)
{
perror("execl error!!!\n");
return 1;
}
}
//子进程2--int execlp(const char *file, const char *arg, ...);
usleep(50000);
if(fork() == 0)
{
printf("Forks 2 is Ok!!! : execlp\n");
if(execlp("ls","ls","-i",NULL) == -1)
{
perror("execlp error!!!\n");
return 1;
}
}
//子进程3--int execle(const char *path, const char *arg,..., char * const envp[]);
usleep(50000);
if(fork() == 0)
{
printf("Forks 3 is Ok!!! : execle\n");
if(execle("/bin/ls","ls","-i",NULL, NULL) == -1)
{
perror("execle error!!!\n");
return 1;
}
}
//子进程4--int execv(const char *path, char *const argv[]);
usleep(50000);
if(fork() == 0)
{
printf("Forks 4 is Ok!!! : execv\n");
if(execv("/bin/ls",arg) == -1)
{
perror("execv error!!!\n");
return 1;
}
}
//子进程5--int execvp(const char *file, char *const argv[]);
usleep(50000);
if(fork() == 0)
{
printf("Forks 5 is Ok!!! : execvp\n");
if(execvp("ls",arg) == -1)
{
perror("execvp error!!!\n");
return 1;
}
}
//子进程6--int execve(const char *filename, char *const argv[],char *const envp[]);
usleep(50000);
if(fork() == 0)
{
printf("Forks 6 is Ok!!! : execve\n");
if(execve("/bin/ls",arg,NULL) == -1)
{
perror("execve error!!!\n");
return 1;
}
}
//子进程7--int execvpe(const char *path, char *const argv[], char * const envp[]);
// usleep(50000);
// if(fork() == 0)
// {
// printf("Forks 7 is Ok!!! : execvpe\n");
// if(execvpe("/bin/ls",arg,NULL) == -1)
// {
// perror("execvpe error!!!\n");
// return 1;
// }
// }
usleep(50000); //不添加usleep(50000),终端会出现输出混乱
return 0;
}
输出:
举个例子:注释掉最后的延时,输出
当然:修改延时也会有不同结果,还与代码量有关