linux进程替换(下)

一、替换原理:

用fork创建子进程后执行的是和父进程相同的程序,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。这里写图片描述

二、替换函数:

   #include<unistd.h>
1int execl(const char  *path//路径,const char *arg//命令怎么输就怎么填,...必须以NULL结束);
2int execlp(const char *file,const char *arg,...);
3int execle(const char *path,const char *arg,...char *const envp[]);
4int execv(const char *path,char*const argv[]);
5int execvp(const char *file,char *const argv[]);
6int execve(const char *path,char *const argv[],char *const envp[]);

1、int execl(const char *path//路径,const char *arg//命令怎么输就怎么填,…必须以NULL结束);

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id==0){//child
  9         sleep(1);                                                                                                 
 10         execl("/bin/ls","ls","-a","-l",NULL);
 11         exit(0);
 12     }else if(id>0){//father
 13         pid_t ret=wait(NULL);
 14         printf("wait child success!: %d\n",ret);
 15 
 16     }
 17     return 0;
 18 }

程序运行:
这里写图片描述
系统命令:
这里写图片描述

结论:运用execl函数模拟实现了ls -a -l的命令,完成了进程替换。

2、int execlp(const char *file,const char *arg,…);

 execlp("ls","ls","-a","-l",NULL);

这里写图片描述

结论:效果和exec一样。

3、int execv(const char *path,char*const argv[]);

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {     
  7     pid_t id=fork();   
  8     if(id==0){//child
  9         sleep(1);
 10        // execl("/bin/ls","ls","-a","-l",NULL);
 11       //  execlp("ls","ls","-a","-l",NULL);
 12         char *myargv[]={
 13             "ls","-a","-l","-n",NULL,
 14         }; 
 15         execv("/bin/ls",myargv);                                                                                  
 16         exit(0);
 17     }else if(id>0){//father
 18         pid_t ret=wait(NULL); 
 19         printf("wait child success!: %d\n",ret);
 20 
 21     }
 22     return 0; 
 23 }

这里写图片描述
结论:

运用execvp函数模拟实现了ls -a -l -n的命令,完成了进程替换。

4、int execvp(const char *file,char *const argv[]);

execvp("ls",myargv);

这里写图片描述
结论:

execvp与execv运行结果一样

5、int execle(const char *path,const char *arg,…char *const envp[]);

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id==0){//child
  9         sleep(1);
 10        // execl("/bin/ls","ls","-a","-l",NULL);
 11       //  execlp("ls","ls","-a","-l",NULL);
 12         char *myargv[]={
 13          "ls","-a","-l","-n",NULL,           
 14         };
 15         char *myenv[]={
 16             "MYPATH=/home/ad/code/30class/day57_进程替换/a.out",
 17             NULL,
 18         };
 19         execle("/home/ad/code/30class/day57_进程替换/a.out","a.out",NULL,myenv);
 20        // execv("/bin/ls",myargv);
 21         // execvp("ls",myargv);
 22         exit(0);
 23     }else if(id>0){//father
 24         pid_t ret=wait(NULL);
 25         printf("wait child success!: %d\n",ret);
 26 
 27     }
 28     return 0;
 29 }             

这里写图片描述

扫描二维码关注公众号,回复: 860309 查看本文章

结论:在execle.c里打印了一长串hello,world!,生成可执行程序./a.out,用execle函数将a.out一替换,子进程就执行了a.out的功能。

6、int excve(const char *path,char *const argv[],char *const envp[]);

  1 #include<stdio.h>                                                                                                 
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id==0){//child
  9         sleep(1);
 10        // execl("/bin/ls","ls","-a","-l",NULL);
 11       //  execlp("ls","ls","-a","-l",NULL);
 12         char *myargv[]={
 13         "ls","-a","-l",NULL,
 14         };
 15         char *myenv[]={
 16             "MYPATH=/home/ad/code/30class/day57_进程替换/a.out",
 17             NULL,
 18         };
 19        // execle("/home/ad/code/30class/day57_进程替换/a.out","a.out",NULL,myenv);
 20         execve("/bin/ls",myargv,myenv);
 21         // execvp("ls",myargv);
 22        // execve("/home/ad/code/30class/day57_进程/a.out ","a.out",NULL,myenv);
 23         exit(0);
 24           }else if(id>0){//father
 25         pid_t ret=wait(NULL);
 26         printf("wait child success!: %d\n",ret);
 27 
 28     }
 29     return 0;
 30 }                  

程序运行:
这里写图片描述
命令执行:

这里写图片描述
结论:

观察运行结果发现两者实现的功能基本一致。

三、函数解释:

  • 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
  • 如果调用出错则返回-1
  • exec函数只有出错的返回值而没有成功的返回值。

四、命名理解:(为了便于记忆)

  • l(list):表示参数采用列表
  • v(vector):参数用数组
  • p(path):有p自动搜索环境变量PATH
  • e(env):表示自己维护环境变量

五、

这里写图片描述

六、

事实上,只有execv是真正的系统调用,其他五个函数最终都调用execve,他们的关系如下图:

这里写图片描述

七、自行实现一个Shell

这里写图片描述

代码:

1 #include<stdio.h>                                    
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<ctype.h>
  5 #include<sys/wait.h>
  6 #include<string.h>
  7 void do_exec(char argc,char **argv)
  8 {
  9     pid_t pid=fork();
 10     if(pid==0){
 11         execvp(argv[0],argv);
 12         perror("execvp");
 13     }
 14     wait(NULL);
 15 }
 16 void do_parse(char *buf)
 17 {
 18     char*argv[8]={};
 19     int argc=0;
 20     int i;
 21     int status=0;
 22     for(i=0;buf[i]!=0;i++)
 23     {
 24         if(status==0&&!isspace(buf[i]))//判断是否为空格
 25         {
 26             argv[argc++]=buf+i;
 27             status=1;
 28         }
 29         else if(isspace(buf[i]))                     
 30         {
 31             status=0;
 32             buf[i]=0;
 33         }
 34     }
 35     do_exec(argc,argv);//argv第一个参数为ELF,第二个>    参数为命令,以NULL结束
 36 }
 37 int main()
 38 {
 39     char buf[1024]={};
 40     while(1){
 41         printf("my shell>");
 42         memset(buf,0x00,sizeof(buf));
 43     while(scanf("%[^\n]%*c",buf)==0)  {
 44         //表示读入一行字符串。
 45         //^表示"非"[^\n]表示读入换行字符就结束读入
 46         //*表示该输入项读入后不赋予任何变量,即
 47         //scanf("%*[^\n]%*c")表示跳过一行字符串。
 48     
 49         printf("myshell>");
 50         while (getchar()=='\n');
 51     }
 52         do_parse(buf);
 53         
 54     }
 55 }                              

运行效果:

这里写图片描述
结论:简易实现了一个小型shell,运用函数调用替换了命令执行的效果。

猜你喜欢

转载自blog.csdn.net/adzn1/article/details/80234139