自编shell命令解释器

来源:互联网 发布:mac win8.1 iso 下载 编辑:程序博客网 时间:2024/05/16 04:50

通过几个模型学习shell命令解释器,并尝试自己编写简易的shell

一、确定main函数

明确要做的功能,基本确定几个大函数:

void InitialEnv();                  //initial environmentvoid PrintSignal();             //print informationvoid GetInput();                    int CommandTransform();     //return 1 for errorvoid Clear();                           //clear last command

其中,自己做的前面两个函数可以合并(读者可自行优化)

int main(void){        printf("\n      Hello my guester!\n");        while(TRUE){        InitialEnv();           //initial comply's emvironment        PrintSignal();          //print sth to recognize user to input commands        GetInput();                 if (strcmp(cmd[0],"exit")==0)   //exit         {            printf("\n         Good bye!\n");            break;        }          if(CommandTransform())                  printf("input error:  undefined command\n");        Clear();    }    return 0;}

大纲完成后自己就开始列写所需的全局变量了:

char *cmds;         //commandint cmds_len;       //command's lengthchar **cmd;         //every commands' wordint cmd_num;        //number of commands' wordsint pip;            //how many pipes in command

二、功能函数的实现:
先看前两个函数,功能比较简单:
这里写图片描述
把主机名和当前目录打印一下并打印输入提示符等待输入;代码如下:

void PrintSignal(){    uid_t my_uid;    struct passwd *my_info;    my_info =getpwuid( getuid() );      char env[50];    getcwd(env,50);                         printf( "%s=> %s$ ", my_info->pw_name,env);    }

其中getpwuid()函数可以得到my_uid的各个属性,在这里使用获得主机名。getcwd()函数用以输出当前目录。

void InitialEnv(){    int i=0;    while((cmds = (char*)malloc(sizeof(char)*100))==0);    while((cmd = (char**)malloc(sizeof(char*)*20))==0);    while(i<20) {    while((cmd[i] =(char*)malloc(sizeof(char)*40))==0);         i = i + 1;    }    cmd_num = 0;    pip = 0;}

初始化环境函数:为存储指令的字符指针申请动态空间(malloc函数)

将输入存入字符串:

void GetInput(){    int i = 0;    int j = 0;    //freopen("/dev/tty","r",stdin);        gets(cmds);                             while (cmds[i]!= '\0')                          {        if(cmds[i]!=' ')            cmd[cmd_num][j++]=cmds[i];        else        {            if ((cmds[i+1]!='\0')&&(cmds[i+1]!=' '))                cmd_num++;            j = 0;        }        i++;    }    cmd_num++;  }

gets()函数得到输入的字符串 以’\n’结束

接下来实现比较复杂的解释输入的“指令”的函数,以下是包含了管道的实现的代码,可能比较繁冗,读者看思路即可:
函数思路:
当还有命令词未判断时循环:判断是否为第一个参数->判断是否包含管道->执行相应的命令(内部和外部,其中外部命令是指在unix操作系统下以文件的形式存在的命令函数,故可用fork-execve-wait-exit模型来调用,切记要让子进程exit)

int CommandTransform(){    int fd[10][2];    int pip = -1;    int i = 0;    pid_t pid;    if (strlen(cmd[0])!=0)    while(i<cmd_num)    {        if (strcmp(cmd[i],"cd") == 0)        {               if (i==0)            {                int fp;                if (strlen(cmd[1])==0)  return 0;       //cd command can't use the pipe '|'                if(strlen(cmd[2])!=0)   return 1;                const char* p = cmd[1];                if((fp=open(p,O_RDONLY)) < 0)           //find the path                        {                                printf("Can not open the directory %s\n",cmd[1]);                                return 0;                        }                if (fchdir(fp) < 0)                 //call fchdir() to change dir                {                    printf("cd failed,try again\n");                    return 0;                }                return 0;            }            else             {                close(0);                dup2(fd[pip][0],0);;                close(fd[pip][1]);                read(fd[pip][0],cmd[i+1],40);                dup2(0,fd[pip][0]);                const char* p = cmd[i+1];                int fp;                if((fp=open(p,O_RDONLY)) < 0)           //find the path                        {                                printf("Can not open the directory %s\n",p);                                return 0;                        }                if (fchdir(fp) < 0)                 //call fchdir() to change dir                {                    printf("cd failed,try again\n");                    return 0;                }                return 0;            }        }        else if (strcmp(cmd[i],"echo") == 0)        {            if (i==0)            {                if (strlen(cmd[2])==0)                {                    printf("%s\n",cmd[i+1]);                    return 0;                       }                else if (strcmp(cmd[2],"|")==0)                {                    if(pipe(fd[++pip])<0)                      {                          printf("pipe error!/n");                              return 0;                      }                      if((pid = fork())<0)                      {                              printf("fork error!/n");                              return 0;                      }                      else if(pid == 0)                    {                        close(1);                        dup2(fd[pip][1],1);                        close(fd[pip][0]);                        write(fd[pip][1],cmd[1],40);                        exit(0);                    }                    else if (pid >0)                    {                        waitpid(pid,NULL,0);                        i+=3;                    }                }                else return 1;            }            else             {                if(strlen(cmd[i+1])==0)                {                    close(0);                    dup2(fd[pip][0],0);                    close(fd[pip][1]);                    read(fd[pip][0],cmd[i+1],40);                    dup2(0,fd[pip][0]);                    printf("%s\n",cmd[i+1]);                    return 0;                }                else if (cmd[i+1]!="|")                {                    printf("input --error!\n");                    return 0;                }                else                {                    close(0);                    fd[pip][0]=dup(0);                    close(fd[pip][1]);                    read(fd[pip][0],cmd[i+1],40);                    if(pipe(fd[++pip])<0)                      {                          printf("pipe error!/n");                              return 0;                      }                    close(1);                    fd[pip][1] = dup(1);                    close(fd[pip][0]);                    write(fd[pip][1],cmd[i+1],40);                      i += 2;                }            }        }        else if (strcmp(cmd[i],"wc") == 0)        {            if (i==0)            {                FILE *fp;                int c;                    int res_current[3]={0};                             const char* p = cmd[1];                if((fp=fopen(p,"r"))==(FILE*)NULL)                    {                             c=3;                   //"wc " takes 3 room                         while(cmds[c]!='\0')                         {                        int flag;                        res_current[2]++;                        if(c=='\n')                        {                            res_current[0]++;                        }                                    c++;                                }                                           printf("line: %d  word: %d  character: %d\n",res_current[0],cmd_num-1,res_current[2]);                    return 0;                            }                            c=fgetc(fp);                        //file-get-char function                    while(c!=EOF)                    {                    int flag;                    res_current[2]++;                    if(c=='\n')                    {                        res_current[0]++;                    }                    if(c=='\t' || c== ' ' || c=='\n')                    {                                if(flag==0)                                {                                    res_current[1]++;                                        flag=1;                            }                    }                        else flag=0;                                  c=fgetc(fp);                            }                            fclose(fp);                                         printf("line: %d  word: %d  character: %d        in '%s'\n",res_current[0],res_current[1],res_current[2],p);                return 0;            }            else             {                if((pid = fork())<0)                  {                      printf("fork error!/n");                          return 0;                  }                  if(pid == 0)                {                    FILE * fp;                    close(0);                    dup2(fd[pip][0],0);                    close(fd[pip][1]);                    read(fd[pip][0],cmd[i+1],40);                    dup2(0,fd[pip][0]);                        int res_current[3]={0};                         if (strlen(cmd[i+1])==0)                    {                        printf("open error!\n");                        return 0;                    }                    if((fp=fopen(cmd[i+1],"r"))==(FILE*)NULL)                    {                                    int c=0;                                                    while(cmd[i+1][c]!='\0')                                {                            int flag;                            res_current[2]++;                            if(c=='\n')                            {                                res_current[0]++;                            }                                if(c=='\t' || c== ' ' || c=='\n')                                {                                        res_current[1]++;                            }                                             c++;                                    }                                               printf("line: %d  word: %d  character: %d\n",res_current[0]+1,res_current[1]+1,res_current[2]);                        exit(0);                    }                    else                     {                        int c=fgetc(fp);                    //file-get-char function                                while(c!=EOF)                                {                            int flag;                            res_current[2]++;                            if(c=='\n')                            {                                res_current[0]++;                            }                                if(c=='\t' || c== ' ' || c=='\n')                                {                                        res_current[1]++;                            }                                            c=fgetc(fp);                                    }                                    fclose(fp);                                                 printf("line: %d  word: %d  character: %d        in '%s'\n",res_current[0],res_current[1],res_current[2],cmd[i+1]);                        exit(0);                    }                }                else if (pid > 0) waitpid(pid,NULL,0);                return 0;            }        }        else if (strcmp(cmd[i],"ls") == 0)        {            if (i==0)            {                if (strlen(cmd[1])==0)                {                    char *argv[]={"ls","-al",(char*)0};                     char *envp[] = {"PATH=/bin",0};                    if((pid = fork())==0)                    {                        execve("/bin/ls",argv,envp);                        exit(0);                    }                    else if (pid > 0) waitpid(pid,NULL,0);                    return 0;                       }                else if(cmd[1]=="|")                {                       if(pipe(fd[++pip])<0)                      {                          printf("pipe error!/n");                              return 0;                      }                      char *argv[]={"ls","-al",(char*)0};                     char *envp[] = {"PATH=/bin",0};                    if((pid = fork())==0)                    {                        close(1);                        dup2(fd[pip][1],1);                        close(fd[pip][0]);                        execve("/bin/ls",argv,envp);                        exit(0);                    }                    else if (pid > 0) waitpid(pid,NULL,0);                    i+=2;                   }                else                {                    if (cmd[2]=="|")                    {                        if(pipe(fd[++pip])<0)                          {                              printf("pipe error!/n");                                  return 0;                          }                          char *argv[]={"ls","-al",(char*)0};                         char *envp[] = {"PATH=/bin",0};                        if((pid = fork())==0)                        {                            close(1);                            dup2(fd[pip][1],1);                            close(fd[pip][0]);                            if  (chdir(cmd[1])==-1)                             {                                printf("no such directory.\n");                                exit(0);                                            }                            execve("/bin/ls",argv,envp);                            exit(0);                        }                        else if (pid > 0) waitpid(pid,NULL,0);                        i+=2;                       }                    else if(strlen(cmd[2])==0)                    {                        char *argv[]={"ls","-al",(char*)0};                         char *envp[] = {"PATH=/bin",0};                        if((pid = fork())==0)                        {                            if  (chdir(cmd[1])==-1)                             {                                printf("no such directory.\n");                                exit(0);                                            }                            execve("/bin/ls",argv,envp);                            exit(0);                        }                        else if (pid > 0) waitpid(pid,NULL,0);                        return 0;                    }                    else return 1;                }             }            else                        //   ls  i!=0            {                if(strlen(cmd[i+1])==0)                {                    char *argv[]={"ls","-al",(char*)0};                     char *envp[] = {"PATH=/bin",0};                    close(0);                    dup2(fd[pip][0],0);                    close(fd[pip][1]);                    read(fd[pip][0],cmd[i+1],40);                    dup2(0,fd[pip][0]);                    if (strlen(cmd[i+1])==0)                     {                        printf("error: ls needs a dir input.\n");                        return 1;                    }                    if((pid = fork())==0)                    {                        if  (chdir(cmd[i+1])==-1)                           {                            printf("no such directory.\n");                            exit(0);                                        }                        execve("/bin/ls",argv,envp);                        exit(0);                    }                    else if (pid > 0) waitpid(pid,NULL,0);                    return 0;                }                else if (cmd[i+1]=="|")                {                    char *argv[]={"ls","-al",(char*)0};                     char *envp[] = {"PATH=/bin",0};                    close(0);                    dup2(fd[pip][0],0);                    close(fd[pip][1]);                    read(fd[pip][0],cmd[i+1],40);                    if(pipe(fd[++pip])<0)                      {                          printf("pipe error!/n");                              return 0;                      }                    if((pid = fork())==0)                    {                        close(1);                        dup2(fd[pip][1],1);                        close(fd[pip][0]);                        if  (strlen(cmd[i+1])!=0&&chdir(cmd[i+1])==-1)                          {                            printf("no such directory.\n");                            exit(0);                                        }                        execve("/bin/ls",argv,envp);                        exit(0);                    }                    else if (pid>0) waitpid(pid,NULL,0);                    i+=2;                }                else return 1;            }        }else return 1;    }}

最后一个清零函数主要来将字符串清零,以避免对下次输入造成影响。

void Clear(){    int i=0;    memset(cmds, 0, sizeof(char *));                //clear cmds    while (i < cmd_num)         memset(cmd[i++], 0, sizeof(char *));            //clear cmd[i]    memset(cmd, 0, sizeof(char **));                //clear cmd }

其中涉及到的头文件如下:

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <pwd.h>#include <fcntl.h>#include <string.h>#include <unistd.h>

运行截图:
欢迎界面
echo
ls
wc
cd
管道
exit
至此,一个简单的shell命令解释器就完成了,有几个涉及到管道的蛋疼的功能还是有点烂尾,读者可在此基础上修改。

0 0
原创粉丝点击