-
2022-03-23 18:27:56
fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容。我们能否让子进程执行一个新的程序呢?exec函数族就提供了一个在进程中执行另一个程序的方法。它可以根据指定的文件名或目录名找到可执行文件,并用他来取代当前进程的数据段、代码段和堆栈段。在执行完后,当前进程除了进程号外,其他内容都被替换。
头文件:#include <unistd.h>
函数原型:
int execl(const char*path, const char *arg, ...); //1. 查找方式:完整的文件目录路径;2. 参数传递方式:逐个列举(list)
int execv(const char*path, const char *const arg[]); //2. 参数传递方式:指针数组传递(vertor)
int execle(const char*path, const char *arg, ..., char *const envp[]); //3. 使用默认的环境变量(environment),在envp[]中指定当前进程使用的环境变量
int execve(const char*path, const char *const arg[], char *const envp[]);
int execlp(const char*file, const char *arg, ...); //1. 查找方式:文件名
int execvp(const char*file, const char *const arg[]);
exec函数名对应名称:
前四位:exec
第五位
l:参数传递为逐个列举方式
v:参数传递为构造指针数组的方式
第六位:
e:可传递新进程环境变量
p:可执行文件查找方式为文件名
函数返回值:-1:出错
如何使用文件名的方式查找可执行文件,同时使用参数列表的方式
这里使用的函数是execlp()
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> int main() { pid_t pid=fork(); if(pid==0) { if((ret=execlp("ps","ps","-ef",NULL))<0) //相当于调用了“ps -ef”命令 { printf("execlp error\n"); } }
使用完整的文件目录来查找对应的可执行文件。
这里使用的函数是execl()
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { if(fork()==0) { if(execl("/bin/ps","ps","-ef",NNULL)<0); //目录必须以“/”开头,否则将视其为文件名 { printf("execl error\n"); } } }
利用execle()将环境变量添加到新建的子进程中
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { char *envp[]={"PATH=/tmp","USER=harry",NULL}; //命令行参数列表,必须以NULL结尾 if(fork()==0) { if(execle("/usr/bin/env","env",NULL,envp)<0) //env是查看当前进程环境变量的命令 { printf("execle error\n"); } } }
使用execve()函数,通过构造指针数组的方式来传递参数
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { char *arg[]={"env",NULL}; char *envp[]={"PATH=/tmp","USER=harry",NULL}; if(fork()) { if(execve("/usr/bin/env",arg,envp)<0) { printf("execve error\n"); } } }
更多相关内容 -
exec函数族的使用
2021-01-19 22:45:47作者:王姗姗,华清远见嵌入式学院... 下面来看下exec函数族: #include int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(cons -
exec函数族
2021-02-15 23:42:11exec函数族一、exec函数族介绍二、exec函数族作用图解三、exec函数族 一、exec函数族介绍 exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个...一、exec函数族介绍
- exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。
- exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样,颇有些神似“三十六计”中的“金蚕脱壳”。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回-1,从原程序的调用点接着往下执行。
二、exec函数族作用图解
三、exec函数族
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[]);
int execve(const char *filename, char *const argv[], char *const envp[]);
参数 意义 l(list) 参数地址列表,以空指针结尾 v(vector) 存有各参数地址的指针数组的地址 p(path) 按 PATH 环境变量指定的目录搜索可执行文件 e(environment) 存有环境变量字符串地址的指针数组的地址 -
linux exec函数族
2022-04-24 11:59:07目录回顾exec 函数族exec 函数族的第一种函数说明和实验exec 函数族的第二种函数说明和实验 回顾 1 父进程调用 frok 函数 克隆出子进程 并且给他拷贝了空间 2 两者操作互不影响 且 内存不能共享 。 继续冲 exec ...回顾
1 父进程调用 frok 函数 克隆出子进程 并且给他拷贝了空间 2 两者操作互不影响 且 内存不能共享 。 继续冲
exec 函数族
前面说的 父进程调用 frok 函数 克隆出子进程 并且给他拷贝了空间 两者操作互不影响 且 内存不能共享 。 这样会导致浪费了空间内存 如果用exec 就会节省空间 并且会多执行一个命令 或者更多命令
exec 函数族的第一种函数说明和实验
path :执行程序路径 arg :执行程序参数 第一个 arg:占位 占位:占位符的意思 随意写就行了 最好和执行参数一样 为了好区分 后面的arg: 命令参数 多少都行 最后以NULL 结尾就行了
直接操作
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/wait.h> int a=100; int main() { pid_t a; a=fork(); if(a>0) { a+=200; printf("!!!A=%d\n",a); printf("father pid is %d\n",getpid()); } else if(a==0) { a-=50; printf("*****a=%d\n",a); printf("child pid is %d ppid is %d \n",getpid(),getppid()); } execl("/bin/ls","ls","-l","NULL");//多余命令 不占用空间 return 0; }
如果只是实现一个命令参数
/bin/ls :执行的程序路径 ls :执行参数(可以不要 也可以随意 只是作为辅助作用) -l 是命令参数 以 NULL结尾 (execl 函数 的 绝对路径选到不能选为止)
多执行 hello.c 呢
第一
第二
gcc hello.c -o hello./hello 运行可执行文件 . 为命令 / 在当前目录下 找到 xxx文件 hello 为命令参数
怎么改呢
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/wait.h> int a=100; int main() { pid_t a; a=fork(); if(a>0) { a+=200; printf("!!!A=%d\n",a); printf("father pid is %d\n",getpid()); } else if(a==0) { a-=50; printf("*****a=%d\n",a); printf("child pid is %d ppid is %d \n",getpid(),getppid()); } execl("/home/ycy/process/hello",“hello”,"hello",NULL); return 0; }
因为 hello 就是命令参数了 所以占位符可以不写 写也可以 写法 2 excel("/home/ycy/process/hello","hello",NULL);
exec 函数族的第二种函数说明和实验
和excel 少了一个参数而已 少了一个特定路径
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/wait.h> int a=100; int main() { pid_t a; a=fork(); if(a>0) { a+=200; printf("!!!A=%d\n",a); printf("father pid is %d\n",getpid()); } else if(a==0) { a-=50; printf("*****a=%d\n",a); printf("child pid is %d ppid is %d \n",getpid(),getppid()); } excelp("ls","ls","-l","NULL");//多余命令 不占用空间 return 0; }
-
Linux下的exec函数族
2021-11-27 23:14:28创建子进程后,我们并不希望子进程执行父进程后续相同的内容,这时我们可以用exec函数族进行。 exec函数族 Linux下的exec函数族,是指6个以exec开头的函数。分别是 int execl(const char *path,const char *arg,...)...引入
创建子进程后,我们并不希望子进程执行父进程后续相同的内容,这时我们可以用exec函数族进行子进程的执行内容替换。
exec函数族
Linux下的exec函数族,是指6个以exec开头的函数。分别是
int execl(const char *path,const char *arg,...) int execv(const char *path,char *cosnt arg[]) 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[]);
复习:牢记const修饰的是谁?指针标记的优先级低于偏移符号[]。
const char *p
:p是一个指针,指向常字符类型
char const *p
:同上,const修饰的是*p
char * const p
:p是一个常指针,指向字符类型。const修饰的是p
char *p[]
:p是一个数组,其内容是字符指针
char (*p)[]
:p是一个指针,指向的内容是字符数组(字符串)
char * const p[]
:p是一个数组,数组的内容是常字符指针我们介绍最常用的第一个程序:
int execl(const char *path,const char *arg,...)
执行原理
为什么说exec函数族可以使子进程执行不同的程序呢?
——“换核不换壳”:进程在调用exec函数时,进程用户空间的代码和数据空间的代码会完全被新的替代。也就是说原有的text和data会被替换掉,但是调用exec函数并不会产生新的进程,也不会改变PID。
直白地讲,就是原有的箱子不变。但是调用exec函数后,其中原有的苹果被换成了梨。使用场景
- 进程认为自己不能再为系统和用户作出任何贡献时,就可以调用任何exec函数族让自己重生
- 如果一个进程想要执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。
我们依旧举一些例子:
//main.c文件 #include<unistd.h> #include<stdio.h> #include<stdlib.h> int main(void) { //int execl(const char *pathname, const char *arg, ... // /* (char *) NULL */); //第一个参数是要执行的执行文件的路径(包含文件名),第二个是要执行文件的文件名 //之后的变长参数就是要带的参数。最后要以(char *)NULL作为最后一个参数 pid_t pid; pid=fork(); if(pid<0) { printf("process create failed!"); } else if(pid == 0) { printf("This is child process!"); printf("PID=%d parent PID=%d\n",getpid(),getppid()); execl("/home/czc/Desktop/LinuxExp/process/subproc","subproc",(char *)NULL); exit(1); } else { printf("This is parent process!"); printf("PID=%d Its child PID=%d\n",getpid(),pid); } printf("This is father process remaining part!\n"); return 0; }
//./subproc.c文件 #include<stdio.h> int main(void) { printf("enter a new subProcess!\n"); return 0; }
调用main.c编译的可执行文件结果如下:
可以发现,父进程剩下的部分,子进程并没有执行。子进程在调用exec函数族后,就只执行subproc.c编译出来的可执行文件了。这里使用exit(1)
的目的只是在exec调用失败后,也主动结束子进程。命令即可执行文件
之前已经提到,Linux下的命令就是可执行文件。那么同样地,我们在调用exec函数族时不仅可以使用我们自己编写的可执行文件,也可以调用系统命令(也就是系统自带的可执行文件)。我们对上面的C源文件稍作修改:
//main.c文件 #include<unistd.h> #include<stdio.h> #include<stdlib.h> int main(void) { //int execl(const char *pathname, const char *arg, ... // /* (char *) NULL */); //第一个参数是要执行的执行文件的路径(包含文件名),第二个是要执行文件的文件名 //之后的变长参数就是要带的参数。最后要以(char *)NULL作为最后一个参数 pid_t pid; pid=fork(); if(pid<0) { printf("process create failed!"); } else if(pid == 0) { printf("This is child process!"); printf("PID=%d parent PID=%d\n",getpid(),getppid()); //ls命令在路径/bin/下 execl("/bin/ls","ls","-al",(char *)NULL); exit(1); } else { printf("This is parent process!"); printf("PID=%d Its child PID=%d\n",getpid(),pid); } printf("This is father process remaining part!\n"); return 0; }
-
Linux中使用exec函数族详解及示例代码 | 嵌入式Linux应用开发篇 – 03
2021-01-06 10:38:261.exec函数族 exec 为 execute(执行),exec 函数族用来替换调用进程所执行的程序,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行,替换前后进程的 PID 不会改变。 exec函数族中包括6个... -
exec函数族实例解析
2021-07-18 21:30:39exec函数族实例解析 fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这... -
进程——exec函数族
2022-03-21 23:36:20一.exec函数族的简介 父进程创建子进程之后,子进程和父进程执行相同的代码,但是实际的开发中,需要让子进程独立出来做一些事情,那么就运用到了exec函数族。 二.函数族的举例 ① execl/execlp int execl(const ... -
exec函数族以及进程的退出与同步
2022-05-12 17:26:35exec函数族,进程的退出,进程的同步,特殊进程的危害 -
23.Linux exec函数族
2021-10-11 16:45:00使用fork函数创建的子进程中包含的程序代码完全相同,只是能根据fork函数...调用exec函数族一般与fork()函数一起使用:使用fork()函数创建进程,使用exec函数族修改进程任务。调用这两个函数后,进程与其中数据的变化情 -
EDA/PLD中的exec函数族的使用
2020-11-09 02:00:12exec用被执行的程序完全替换调用它的程序... 下面来看下exec函数族: #include int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(cons -
Linux系统编程 -- exec函数族
2021-05-04 01:54:46完成这样的操作:需要使用到exec函数族,去执行另外一个程序,进程调用exec函数时,进程的 用户空间代码和数据会完全被新的程序代替,这并没有去创建新的进程,而是代码段和数据段的替换 2.函数如下: int execl... -
exec函数族 与 system函数
2021-10-06 15:40:14exec函数族中的函数可以实现在一个进程中执行另一个进程,这个进程可以是可执行文件、shell命令、shell脚本,它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。... -
exec函数族用法总结
2019-11-19 20:39:151、exec函数说明 fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。...在fork后的子进程中使用exec函数族... -
【Linux】进程控制(exec函数族)的理解和使用
2022-03-20 19:05:11exec函数族使用的总结 有了exec函数族我们就可以用它来调用任何程序,也就是说,你还可以在C/C++,可以调用其他任何语言,比如python,Java等程序; 这些exec函数的接口函数本质是没有任何差别的,只是参数选项不同... -
【Linux】应用篇七--exec函数族和守护进程
2022-03-22 14:58:52应用篇七--exec函数族和守护进程一、exec函数族1、exec函数族2、execl / execlp3、execv / execvp4、system二、守护进程1、守护进程特点守护进程的含义守护进程的特点相关概念2、创建守护进程(1)创建子进程,父... -
Linux 软件系列之九——exec函数族和system函数调用
2021-05-13 02:58:141.exec函数族可以实现在一个进程中启动另一个程序的功能。系统内核会使用新的程序替换原有进程中使用的程序。开始新程序的执行。新进程和原有的进程号相同。调用exec函数后,代码段中的内容被新进程的代码替换,接着... -
exec函数族和wait函数解决僵尸进程
2022-05-11 11:03:12【案例 1】若子进程p1是其父进程p的先决进程,基于wait函数使得进程同步。 #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> int main(){ pid_t tempPid, tempW; tempPid = ...