LINUX SHELL 设计实现

flaty 13年前

没啥可说的,直接贴原码:
LINUX的作业。嘿。

设计并实现一个Linux下的的交互式shell命令解释器:MyShell;以模拟unix/linux系统下的完善的bash shell的功能。不需要具备非常完备的shell功能。主要有如下功能:

<!--[if !supportLists]-->l        <!--[endif]-->初始化环境,主要是默认搜索路径、history循环数组、作业列表

<!--[if !supportLists]-->l        <!--[endif]-->打印命令提示符;

<!--[if !supportLists]-->l        <!--[endif]-->接受、识别和分析命令提示符后输入的命令行,并创建子程序,在子程序中将其转换为相对的系统调用以调用内核功能实现任务;

<!--[if !supportLists]-->l        <!--[endif]-->能实现内部命令,包括:exit(退出shell)、historycdjobsbgfg

<!--[if !supportLists]-->l        <!--[endif]-->能够执行外部命令,并到搜索路径中去查找外部命令对应的执行文件;命令均可带参数;

<!--[if !supportLists]-->l        <!--[endif]-->支持&|<>四个特殊字符及其所代表的功能;

<!--[if !supportLists]-->l        <!--[endif]-->支持前、后台作业控制,包括fg/bg/jobs以及ctrl+c/ctrl+z(挂起、中止和继续运行)。

#include <stdio.h>    #include <unistd.h>    #include <stdlib.h>    #include <sys/wait.h>  #include <string.h>    #include <signal.h>    #include <sys/types.h>    #include<unistd.h>  #include<stdio.h>  #include<stdlib.h>  #include<fcntl.h>  #include<string.h>  #include <errno.h>        #define MAXLEN 128   //命令最大长度      #define HIS_LEN 10   //历史记录最大长度          typedef struct history  //历史记录结点    {     int i;   int start;     int end;     char cmd[HIS_LEN][MAXLEN];    }  history;        typedef struct node{  //作业链表结点         pid_t pid;             char cmd[100];         char state[10];         struct node *next;        }node;        /********************************声明全局变量*********************************/    node *head,*end;  //jobs 链表    history his;   //history 队列    char buf[MAXLEN];  //保存输入命令    char *path[10];   //保存多个环境变量.--pATH    char path_cmd[50];  //保存输入命令的绝对路    int path_sum;   //PATH环境变量个数。    char work_path[100]; //保存当前工作路径             int jobs_count=0;  //当前工作数量    pid_t pid;    //子进程PID    char *argv[10];   //根据空格分解命令的字符指针数组    int cmd_count=0;  //历史记录个数    int stop_flag=0;    //-------------------------------------声明函数----------------------------------------    void print_work_path();      //  打印SHELL 提示符    void print_string(char *);       // 打印字符串  int read_commands(char *);     // 读取命令    void init_envi();       // 初始化环境    void analyse_cmd(char**);     // 分析命令,并根据空格分解之    int cmd_addpath(char *);     // 补全命令            void my_cd(char* );       // CD 命令        void my_history(char *);     // HISTORY 命令    void save_history();      // 保存输入命令历史                  void my_jobs();        // JOBS查看     void my_fg(char *ch,sigset_t *son_set);  // FG命令    void my_bg(char *);         // BG命令    void add_node(int,char*,char *);   // 增加作业结点命令     void father_sig_hander(int );    // 父进程信号处理函数    void reDirect(char *buf);     // 管道重定向  char *instru_divide(char *ch);  void aru_divide(char *instru, char **ch);    //-----------------main-----------------    main (){        int is_bg;  //后台命令标记,后台=0,否则为1。                   init_envi(); //初始化环境           //-------------信号处理---------------                sigset_t son_set;      //设置父进程信号处理函数    struct sigaction father_pact;    father_pact.sa_handler=father_sig_hander;           sigemptyset(&son_set);   //设置子进程屏蔽信号集        sigaddset(&son_set,SIGTSTP);      sigaddset(&son_set,SIGINT);           //-------------接收命令---------------     while(1){      sigprocmask(SIG_BLOCK,&son_set,NULL);    //pid=0;    stop_flag=0;    waitpid(-1,NULL,WNOHANG);  //回收僵尸进程              signal(SIGINT,father_sig_hander);   //为父进程安装信号处理函数      sigaction(SIGTSTP,&father_pact,NULL);                      is_bg=0;           print_work_path();  //打印命令提示符            if (!read_commands(buf)) //不处理空格等无用命令, 并去除命令前后空格!       continue;            save_history(his); //保存命令历史               int flag=cmd_match(buf);    if(flag==1){        //----------管道重定向相关---------               reDirect(buf);     continue;      }        else if(flag==2){         is_bg=1;            }                    analyse_cmd(argv);//解析命令,根据空格分开。               //----------------------------执行内部命令------------------------        if(!strcmp("exit",argv[0])&&argv[1]==NULL)        { puts("goodbye!");exit(0);}        else if(!strcmp("cd",argv[0])){   //------cd         my_cd(argv[1]);         continue;        }        else if(!strcmp("history",argv[0])){ //-------history         my_history(argv[1]);         continue;        }        else if(!strcmp("jobs",argv[0])){  //--------jobs         my_jobs();         continue;        }        else if(!strcmp("fg",argv[0])){   //--------fg         my_fg(argv[1],&son_set);         continue;        }        else if(!strcmp("bg",argv[0])){   //--------bg         my_bg(argv[1]);         continue;        }                     //------------根据pATH补全外部命令,包括当前路径---------        if(cmd_addpath(argv[0])==0){                   strcpy(path_cmd,argv[0]); //如果在PATH没找到,把命令视为绝对路径,直接执行!                //        }             //------------------执行外部命令------------------------                   if((pid=fork())<0)         perror("execute fail!!");                 //-------------子进程--------------        else if(pid==0)        {                          if(execv(path_cmd,argv)==-1)                 puts("cmd not found!!");                       }          //--------------父进程 ----------------        else        {          sigprocmask(SIG_UNBLOCK,&son_set,NULL);         if(is_bg==1)          add_node(pid,argv[0],"running");         else{                     waitpid(pid,NULL,0);                        }        }            }//while              }    //-------------main 结束--------------------------              //--------------初始化环境-----------------------    void init_envi(){     FILE *fp;     char ch,temp[100],*p;     int i=0;     his.end=his.start=0;   jobs_count=0;     stop_flag=0;     head=end=NULL;     if((fp=fopen("./test_profile","r"))==0)         {              perror("init path failure!! exit!!");              exit(1);         }     while((ch=fgetc(fp))!=EOF) temp[i++]=ch;         temp[i]=0;          i=0;     while(temp[i]&&temp[i]!='=') ++i;        strcpy(temp,temp+i+1);         char *delim = ":";     p=strtok(temp, delim);       path[0]=(char *)malloc(strlen(p)+1);        strcpy(path[0],p);        i=1;     while((p=strtok( NULL, delim))!=NULL)           {  path[i]=(char *)malloc(strlen(p)+1);           strcpy(path[i],p);             i++;         }         path_sum=i-1;      }            //------------命令匹配--------------------------------------------------------    int cmd_match(char *buf){     char *ch;     if(strchr( buf, '|')!=NULL||strchr( buf, '<')!=NULL||strchr( buf, '>')!=NULL)      return 1;     else if((ch=strchr( buf, '&'))!=NULL)     { *ch=0 ; return 2;}         }                    //------------打印命令提示--------------------------------    void print_work_path() {     char * user = getlogin();     getcwd(work_path,sizeof(work_path));         printf("<");     print_string(user);     printf("@ ");     print_string(work_path);     printf(">$");    }                //------------读取输入命令------------------------    int  read_commands(char * buf)    {     int i=0;char ch;       //printf("%s",buf);     //gets(buf);       ch=getchar();        if(ch=='\n') return 0;     buf[i++]=ch;   while((ch=getchar())!='\n') buf[i++]=ch;   buf[i]=0;    //puts(buf);   i=0;     while(buf[i]==' '||buf[i]=='\t'&&buf[i]) ++i;     if(buf[i]==0)     return 0;            else {    i=0;      while(buf[i]==' '||buf[i]=='\t') ++i;//去除前面空格      strcpy(buf,buf+i);        //  int j=strlen(buf)-1;  //  while(buf[j]==' '||buf[j]=='\t') j--;  //  buf[j+1]=0;  //puts(buf);  //printf("%d",strlen(buf));    return 1;     }    }                    //----------------------解析命令--------------------    void analyse_cmd(char **argv){     int i=1;     char *delim = "' ','\t'";     argv[0]=strtok(buf, delim);  //puts(argv[0]);     while((argv[i]=strtok( NULL, delim))!=NULL)             i++;             argv[i]=NULL;            }                    //---------------------补全命令-------------------    int cmd_addpath(char * argv){     int i=0;     //char   //puts("!!!!");       //printf("%d\n",path_sum);   strcpy(path_cmd,work_path);//查找当前路径并补全命令      strcat(path_cmd,"/");       strcat(path_cmd,argv);    //puts(path_cmd);      if(!access(path_cmd,F_OK))        return 1;   while(i<path_sum){  //查找pATH并补全命令      strcpy(path_cmd,path[i]);      strcat(path_cmd,"/");                  strcat(path_cmd,argv);  //puts(path_cmd);      if(access(path_cmd,F_OK)==0)       return 1;    i++;     }           return 0;    }                    //---------------常用函数--------------    void print_string(char *p){       printf("%s",p);        }                //---------------内部命令--------------------------------------------        //------------save history------------------      void save_history(){          cmd_count++;     his.start%=HIS_LEN;     his.end%=HIS_LEN;            strcpy(his.cmd[his.end++],buf);        if((his.end)%HIS_LEN==his.start)          his.start++;       }                        //---------------------cd-------------------------    void my_cd(char * para){        if(para==NULL)       chdir("/root");         else if(para!=NULL&&chdir(para)==-1)           perror("dir not exist!!n");          }                    //----------------------history----------------------------    void my_history(char * argv) {     int i=0,len,j;     if(cmd_count<HIS_LEN) len=cmd_count;     else len=HIS_LEN;        j=len;     if(argv==NULL){          for(i=his.start;i<his.start+len;i++)      printf("%d \t%s\n",j--,his.cmd[i%HIS_LEN]);       }         }                    //--------------------作业控制相关-------------------------------      void my_jobs()    { int i=1;     if(head==NULL) {printf("no jobs!!\n");return;}   node *p=head;     while(p->next!=NULL)     {      printf("[%d]- %d  %s \t%s\n",i++,p->pid,p->state,p->cmd);      p=p->next;     }     printf("[%d]+ %d  %s  \t%s\n",i,p->pid,p->state,p->cmd);    }        //-------------------------fg-----------------------        void my_fg(char *ch,sigset_t *son_set){      sigprocmask(SIG_UNBLOCK,son_set,NULL);     if(head==NULL){     //无作业    printf("no  job!!\n");    return;      }   if(ch==NULL){   //    puts("para missing!");   }   else {    //作业放到前台运行      int i=atoi(ch),j=1;          node *p=head,*q;          if(i>2){     while(p->next!=NULL&&j<i-1)       { p=p->next; j++;}       if(p->next==NULL) {      printf("no such job!!\n");      return;     }         }else {           if(i==2&&p->next==NULL)      {printf("no such job!!\n");return;}      }        if(i==1){      if(head==end){              //printf("only one!\n");              p=head;               pid=p->pid;printf("%d\t\t%s\n",pid,p->cmd);       free(p);       head=end=NULL;      }else{      //  printf("i==1!\n");        q=p->next;      pid=head->pid;printf("%d\t\t%s\n",pid,head->cmd);      free(head);      head=q;}    }         else{           //printf("other\n");     q=p->next;     pid=q->pid;     p->next=q->next;     if(q->next==NULL) end=p;//如果是最后一个结点     printf("%d\t\t%s\n",pid,q->cmd);     free(q);      }      jobs_count--;    kill(pid,SIGCONT);    waitpid(pid,NULL,0);               }              }            //-------------------------bg---------------------        void my_bg(char *ch){     if(head==NULL){     //无作业      printf("no  job!!\n");      return;          }     else if(ch==NULL){    //把作业放到后台      puts("para missing!");     }     else{       //根据作业号放至后台运行。          int i=atoi(ch),j=1;      node *p=head;      while(p->next!=NULL&&j++<i) p=p->next;     if(p==NULL) {     printf("no such job!!\n");     return;    }    pid=p->pid;        kill (pid,SIGCONT);    strcpy(p->state,"running");           }          }          //--------------------往作业链表增加结点------------------    void add_node(int pid,char *argv,char *state)    {          node *p;     jobs_count++;     p=(node *)malloc(sizeof(node));     p->pid=pid;     if (stop_flag==0)      strcat(argv," &");     strcpy(p->cmd,argv);        strcpy(p->state,state);        p->next=NULL;             printf("[%d] %d  %s  %s\n",jobs_count,p->pid,p->state,p->cmd);          if(head==NULL){      head=p;end=p;     }else {      end->next=p;      end=end->next;     }            }                //-------------信号处理函数-------------------------------------------    void father_sig_hander(int p){       if(p==SIGINT)     {     kill(pid,SIGTERM);          }     else if(p==SIGTSTP)     {      stop_flag=1;  //printf("%d\n",pid);      kill(pid,SIGSTOP);        add_node(pid,strrchr(path_cmd,'/')+1,"stop");     }    }                 //--------------------管道重定向----------------------------//    //-------------找出管道符位置并返回*-------------------------/  char *instru_divide(char *ch){   char *argu1, *argu2;   char *token[] = {"<",">","|"};   int i = 0, len;    len = strlen(ch);   for(;i<3;i++){    argu1 = strtok(ch,token[i]);    if(strlen(argu1)<len){          break;    }    else{      continue;    }   }   return token[i];  }      //---------------求取execvp函数第二个参数-------------/  void aru_divide(char *instru, char **ch){   int i = 0;   ch[i] = strtok(instru," ");   while(ch[i]&&i<8){    i++;    ch[i] = strtok(NULL," ");   }   ch[i] = (char *)0;//最后一个参数后面指针赋值NULL  }    void reDirect(char *str){   char *instru1 , *instru2 , *token , ch[50];   int pipe_fd[2];    int fid;    strcpy(ch,str);   token = instru_divide(str);//token 为管道符 |、 >、或 <    instru1 = strtok(str,token);//处理前管道符前一个命令    instru2 = strstr(ch,token)+1;//处理前管道符后一个命令   char *prog1[8],*prog2[8];//定义指针数组存储execvp函数第二个参数    aru_divide(instru1,prog1);    aru_divide(instru2,prog2);   pid_t pid[2];   if(strcmp(token,"|")==0){    if(pipe(pipe_fd) < 0){     perror ("pipe failed");     exit (errno);                }      pid[0] = fork();    if(pid[0]<0){     perror("fork error");     exit(1);    }      else if(pid[0]==0){      close(pipe_fd[0]);     dup2(pipe_fd[1], 1);     close(pipe_fd[1]);     execvp(prog1[0], prog1);    }      else{      pid[1] = fork();     if(pid[1]<0){        perror("fork error");        exit(1);       }     else if(pid[1]==0){      close(pipe_fd[1]);      dup2(pipe_fd[0],0);      close(pipe_fd[0]);      if(execvp(prog2[0], prog2)){       close(pipe_fd[0]);       close(pipe_fd[1]);       return;      }     }     close(pipe_fd[0]);     close(pipe_fd[1]);     waitpid(pid[0],NULL,0);     waitpid(pid[1],NULL,0);       }     return;   }    if(strcmp(token,">")==0){     if((fid = open(prog2[0],O_CREAT|O_RDWR|O_TRUNC))==-1){      perror("open error");      exit(1);     }     pid[0] = fork();     if(pid[0]<0){      perror("fork error");      exit(1);     }     else if(pid[0]==0){      dup2(fid,1);      close(fid);      execvp(prog1[0], prog1);     }     else{      waitpid(pid[0],NULL,0);     }     return;   }    if(strcmp(token,"<")==0){    if(access(prog2[0],F_OK)){     perror("file not found");     exit(1);    }    pid[0] = fork();    if(pid[0]<0){     perror("fork error");     exit(1);    }     else if(pid[0]==0){      fid = open(prog2[0],O_RDWR);      dup2(fid,0);      close(fid);      if(execvp(prog1[0], prog1)){       puts("rwewrw");      }     }     else{      waitpid(pid[0],NULL,0);     }     return;   }  }