进程深入学习笔记(3)--进程的程序替换(exec)和一个简单的shell实现

版权声明:本文为博主原创文章,欢迎转载,转载请声明出处! https://blog.csdn.net/hansionz/article/details/83013477

1.进程的程序替换(exec)

(1).替换原理

  • fork创建子进程后执行的是和父进程相同的程序,当然可以执行不同的分支(如果我们用fork创建一个子进程之后让子进程做和父进程同样的事,那么这个子进程没有任何意义)。
  • 所以在fork之后,我们应该调用exec函数用来替换子进程的程序和数据,让子进程执行和负进程不同的程序。当进程调用exec函数时,该进程的用户空间得到代码和数据完全被新的程序替换
  • 调用exec并不创建新的进程

在这里插入图片描述

(2).六种替换函数

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., 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[]);

这6个函数其实可以分为两类:

  • execl:表示参数采用列表的形式例如:execl("/bin/ls","ls","-a","NULL")
  • execv:表示参数采用数组的形式
    例如:
char* myargv[]={"ls","-a,"NULL"};
execv("bin/ls",myargv);
  • p(PATH):可以自动搜索环境变量PATH
  • e(env):需要自己组装环境变量

(3).exec类函数用法

char* const argv[]={"ls","-a","NULL"};
char* const envp[]={"PATH=/bin:/user/bin","NULL"};

execl("/bin/ls","ls","-a","NULL");
execlp("ls","ls","-a","NULL");
execle("/bin/ls","ls","-a","NULL",envp);

execv("/bin/ls",argv);
execvp("ls",argv);
execve("/bin/ls",argv,envp);

注:这6个函数只有execve是真正的系统调用,其他5个函数都是在execve上包装的,它们6个函数有以下的关系。

在这里插入图片描述

2.实现一个简单的shell

(1).shell的功能

  • Linux下,shell为操作系统的外壳,为用户提供了使用操作系统的接口,它是命令语言命令解释程序程序设计语言的统称。
  • 命令解释器:把用户输入的命令翻译给核心,并把核心执行的结果反馈给用户

(2).具体过程

  • 打印一个字符串(包括用户名,主机名,当前文件路径)和shell的提示符(管理员为#,普通用户为$

  • 在提示符后输入一串字符串(命令),它接收用户输入的字符串命令,进行命令分析

  • 派生一个子进程,由子进程实现命令的功能

  • 子进程结束时,再次发出提示符

(3).代码实现

  #include<stdio.h>                                                                                                                                   
  #include<stdlib.h>                                                                                                                                  
  #include<stdlib.h>                                                                                                                                  
  #include<sys/times.h>                                                                                                                               
  #include<wait.h>                                                                                                                                    
  #include<string.h>                                                                                                                                  
  #include<unistd.h>                                                                                                                                  
  #include<pwd.h>                                                                                                                                     
                                                                                                                                                      
  #define MAX 128                                                                                                                                     
  #define NUM 128                                                                                                                                     
  #define BUFNUM 1024                                                                                                                                 
  #define COUNT 16                                                                                                                                    
  //获取用户名                                                                                                                                        
  void GetLoginname(){                                                                                                                                
    struct passwd* pwd=getpwuid(getuid());                                                                                                            
    printf("[%s",pwd->pw_name);                                                                                                                       
  }                                                                                                                                                   
  //获取主机名                                                                                                                                        
  void Gethostname(){                                                                                                                                 
    char name[MAX];                                                                                                                                   
    gethostname(name,sizeof(name));                                                                                                                   
    printf("@%s",name);                                                                                                                               
  }                                                                                                                                                   
  //获取当前文件的路径                                                                                                                                
  void Getpath(){                                                                                                                                     
    char buf[NUM];                                                                                                                                    
    getcwd(buf,sizeof(buf));                                                                                                                          
    char* p=buf+strlen(buf)-1;                                                                                                                        
    while(*p!='/'){                                                                                                                                   
      --p;  
       }                                                                                                                                                 
    ++p;                                                                                                                                              
    printf(" %s]$ ",p);                                                                                                                               
  }                                                                                                                                                   
                                                                                                                                                      
  int main(){                                                                                                                                         
                                                                                                                                                      
    while(1){                                                                                                                                         
      //打印[zsc@localhost MyShell]                                                                                                                   
      GetLoginname();                                                                                                                                 
      Gethostname();                                                                                                                                  
      Getpath();                                                                                                                                      
      fflush(stdout);//不刷新缓冲区会影响下边                                                                                                         
      //输入命令                                                                                                                                      
      char buf[BUFNUM];                                                                                                                               
      fgets(buf,BUFNUM,stdin);                                                                                                                        
      buf[strlen(buf)-1]=0;                                                                                                                           
      //解析命令,把命令分隔成单个字符串放入到myargv中                                                                                                
      char* myargv[COUNT];                                                                                                                            
      int index=0;                                                                                                                                    
      myargv[index++]=strtok(buf," ");                                                                                                                
      char* ret=NULL;                                                                                                                                
      while(ret=strtok(NULL," ")){                                                                                                                    
        myargv[index++]=ret;                                                                                                                          
      }                                                                                                                                               
      myargv[index]=NULL;                                                                                                                             
  
      pid_t id=fork();
      if(id<0){//error
        perror("use fork");
        exit(1);
     }                                                                                                                                               
      //子进程进行程序替换,执行程序                                                                                                                  
      else if(id==0){//child                                                                                                                          
        execvp(myargv[0],myargv);                                                                                                                     
        exit(1);                                                                                                                                      
      }                                                                                                                                               
      //父进程只要等待即可                                                                                                                            
      else{//parent                                                                                                                                   
        waitpid(id,NULL,0);                                                                                                                           
      }                                                                                                                                               
    }                                                                                                                                                 
    return 0;                                                                                                                                         
  }          

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/83013477