今日在完成一个大作业,主要的任务是编写linux下的shell程序,这有助于我们理解什么是shell,还有其实他也***了linux操作系统微内核的概念,下面有几篇还不错的资料,供大家参考。

首先是一篇解析shell原理的文章,对我帮助不大,因为我还没有要编写一个完整的shell的需要,所以只是资料,略看了一下。http://files.linjian.org/articles/bash_study/bash_linjian.html

然后就是下面这两篇文章,里面的代码很不错,它实现了一些shell的基本功能,顺便把他的代码也贴出来看看,缺点是没有实现一些内部命令。

http://www.jiechic.com/archives/24.html

http://www.jiechic.com/archives/25.html

 

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <unistd.h> 
  4. #include <string.h> 
  5. #include <sys/types.h> 
  6. #include <sys/wait.h> 
  7. #include <fcntl.h> 
  8. #include <sys/stat.h> 
  9. #include <dirent.h> 
  10. #define normal      0  /* 一般的命令 */ 
  11. #define out_redirect    1  /* 输出重定向 */ 
  12. #define in_redirect 2  /* 输入重定向 */ 
  13. #define have_pipe   3  /* 命令中有管道 */  
  14.   
  15. void print_prompt();                    /* 打印提示符 */ 
  16. void get_input(char *);                 /* 得到输入的命令 */ 
  17. void explain_input(char *buf, int *argcount, char arglist[100][256]);       /* 对输入命令进行解析 */ 
  18. void do_cmd(int argcount, char arglist[100][256]);      /* 执行命令 */ 
  19. int  find_command(char *);                  /* 查找命令中的可执行程序 */ 
  20.   
  21. int main(int argc, char **argv) 
  22.     int    i; 
  23.     int    argcount = 0; 
  24.     char   arglist[100][256]; 
  25.     //char   **arg = NULL; 
  26.     char   *buf  = NULL; 
  27.     buf = (char *)malloc(256); 
  28.     if( buf == NULL ) { 
  29.         perror("malloc failed"); 
  30.         exit(-1); 
  31.     } 
  32.     while(1) { 
  33.         /* 将buf所指向的空间清零 */ 
  34.         memset(buf, 0, 256); 
  35.         print_prompt(); 
  36.         get_input(buf); 
  37.         /* 若输入的命令为exit或logout则退出本程序 */ 
  38.         if( strcmp(buf,"exit\n") == 0 || strcmp(buf,"logout\n") == 0 ) 
  39.             break
  40.         for (i=0; i < 100; i++) 
  41.         { 
  42.             arglist[i][0]='\0'
  43.   
  44.         } 
  45.         argcount = 0; 
  46.         explain_input(buf, &argcount, arglist); 
  47.         do_cmd(argcount, arglist);   
  48.   
  49.     } 
  50.     if(buf != NULL) { 
  51.         free(buf); 
  52.         buf = NULL; 
  53.     } 
  54.     exit(0); 
  55.   
  56. void print_prompt() 
  57.     printf("myshell$$ "); 
  58.   
  59. /*获取用户输入*/ 
  60. void get_input(char *buf) 
  61.     int len = 0; 
  62.     int ch; 
  63.     ch = getchar(); 
  64.     while (len < 256 && ch != '\n') { 
  65.         buf[len++] = ch; 
  66.         ch = getchar(); 
  67.     } 
  68.     if(len == 256) { 
  69.         printf("command is too long \n"); 
  70.         exit(-1); /* 输入的命令过长则退出程序 */ 
  71.     } 
  72.     buf[len] = '\n'
  73.     len++; 
  74.     buf[len] = '\0';         
  75.   
  76.   
  77. /* 解析buf中的命令,将结果存入arglist中,命令以回车符号\n结束 */ 
  78. /* 例如输入命令为"ls -l /tmp",则arglist[0]、arglist[1]、arglsit[2]分别为ls、-l和/tmp */ 
  79. void explain_input(char *buf, int *argcount, char arglist[100][256]) 
  80.     char    *p  = buf; 
  81.     char    *q  = buf; 
  82.     int number  = 0; 
  83.     while (1) { 
  84.         if ( p[0] == '\n' ) 
  85.             break
  86.         if ( p[0] == ' '  ) 
  87.             p++; 
  88.         else { 
  89.             q = p; 
  90.             number = 0; 
  91.             while( (q[0]!=' ') && (q[0]!='\n') ) { 
  92.                 number++; 
  93.                 q++; 
  94.             } 
  95.             strncpy(arglist[*argcount], p, number+1); 
  96.             arglist[*argcount][number] = '\0'
  97.             *argcount = *argcount + 1; 
  98.             p = q; 
  99.         } 
  100.     } 
  101.   
  102. void do_cmd(int argcount, char arglist[100][256]) 
  103.     int flag = 0; 
  104.     int how = 0;        /* 用于指示命令中是否含有>、<、|   */ 
  105.     int background = 0; /* 标识命令中是否有后台运行标识符& */ 
  106.     int status; 
  107.     int i; 
  108.     int fd; 
  109.     char*   arg[argcount+1]; 
  110.     char*   argnext[argcount+1]; 
  111.     char*   file; 
  112.     pid_t   pid; 
  113.     /*将命令取出*/ 
  114.     for (i=0; i < argcount; i++) { 
  115.         arg[i] = (char *) arglist[i]; 
  116.     } 
  117.     arg[argcount] = NULL; 
  118.     /*查看命令行是否有后台运行符*/ 
  119.     for (i=0; i < argcount; i++) { 
  120.         if (strncmp(arg[i], "&",1) == 0) { 
  121.             if (i == argcount-1) { 
  122.                 background = 1; 
  123.                 arg[argcount-1] = NULL; 
  124.                 break
  125.             } 
  126.             else { 
  127.                 printf("wrong command\n"); 
  128.                 return ; 
  129.             } 
  130.         } 
  131.     } 
  132.     for (i=0; arg[i]!=NULL; i++) { 
  133.         if (strcmp(arg[i], ">") == 0 ) { 
  134.             flag++; 
  135.             how = out_redirect; 
  136.             if (arg[i+1] == NULL) 
  137.                 flag++; 
  138.         } 
  139.         if ( strcmp(arg[i],"<") == 0 ) { 
  140.             flag++; 
  141.             how = in_redirect; 
  142.             if(i == 0) 
  143.                 flag++; 
  144.         } 
  145.         if ( strcmp(arg[i],"|")==0 ) { 
  146.             flag++; 
  147.             how = have_pipe; 
  148.             if(arg[i+1] == NULL) 
  149.                 flag++; 
  150.             if(i == 0 ) 
  151.                 flag++; 
  152.         } 
  153.     } 
  154.     /* flag大于1,说明命令中含有多个> ,<,|符号,本程序是不支持这样的命令的 
  155.        或者命令格式不对,如"ls -l /tmp >" */ 
  156.     if (flag > 1) { 
  157.         printf("wrong command\n"); 
  158.         return
  159.     } 
  160.     if (how == out_redirect) {  /*命令只含有一个输出重定向符号> */ 
  161.         for (i=0; arg[i] != NULL; i++) { 
  162.             if (strcmp(arg[i],">")==0) { 
  163.                 file   = arg[i+1]; 
  164.                 arg[i] = NULL; 
  165.             } 
  166.         } 
  167.     } 
  168.     if (how == in_redirect) {    /*命令只含有一个输入重定向符号< */ 
  169.         for (i=0; arg[i] != NULL; i++) { 
  170.             if (strcmp (arg[i],"<") == 0) { 
  171.                 file   = arg[i+1]; 
  172.                 arg[i] = NULL; 
  173.             } 
  174.         } 
  175.     } 
  176.     if (how == have_pipe) {  /* 命令只含有一个管道符号| */ 
  177. /* 把管道符号后门的部分存入argnext中,管道后面的部分是一个可执行的shell命令 */ 
  178.         for (i=0; arg[i] != NULL; i++) { 
  179.             if (strcmp(arg[i],"|")==0) { 
  180.                 arg[i] = NULL; 
  181.                 int j; 
  182.                 for (j=i+1; arg[j] != NULL; j++) { 
  183.                     argnext[j-i-1] = arg[j]; 
  184.                 } 
  185.                 argnext[j-i-1] = arg[j]; 
  186.                 break
  187.             } 
  188.         } 
  189.     } 
  190.     if ( (pid = fork()) < 0 ) { 
  191.         printf("fork error\n"); 
  192.         return
  193.     } 
  194.     switch(how) { 
  195.         case 0: 
  196.             /* pid为0说明是子进程,在子进程中执行输入的命令 */ 
  197.             /* 输入的命令中不含>、<和| */ 
  198.             if (pid == 0) { 
  199.                 if ( !(find_command(arg[0])) ) { 
  200.                     printf("%s : command not found\n", arg[0]); 
  201.                     exit (0); 
  202.                 } 
  203.                 execvp(arg[0], arg); 
  204.                 exit(0); 
  205.             } 
  206.             break
  207.         case 1: 
  208.             /* 输入的命令中含有输出重定向符> */ 
  209.             if (pid == 0) { 
  210.                 if ( !(find_command(arg[0])) ) { 
  211.                     printf("%s : command not found\n",arg[0]); 
  212.                     exit(0); 
  213.                 } 
  214.                 fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0644); 
  215.                 dup2(fd,1); 
  216.                 execvp(arg[0],arg); 
  217.                 exit(0); 
  218.             } 
  219.             break
  220.         case 2: 
  221.             /* 输入的命令中含有输入重定向符< */ 
  222.             if (pid == 0) { 
  223.                 if ( !(find_command (arg[0])) ) { 
  224.                     printf("%s : command not found\n",arg[0]); 
  225.                     exit(0); 
  226.                 } 
  227.                 fd = open(file,O_RDONLY); 
  228.                 dup2(fd,0); 
  229.                 execvp(arg[0],arg); 
  230.                 exit(0); 
  231.             } 
  232.             break
  233.         case 3: 
  234.             /* 输入的命令中含有管道符| */ 
  235.             if(pid == 0) { 
  236.                 int  pid2; 
  237.                 int  status2; 
  238.                 int  fd2; 
  239.                 if ( (pid2 = fork()) < 0 ) { 
  240.                     printf("fork2 error\n"); 
  241.                     return
  242.                 } 
  243.                 else if (pid2==0) { 
  244.                     if ( !(find_command(arg[0])) ) { 
  245.                         printf("%s : command not found\n",arg[0]); 
  246.                         exit(0); 
  247.                     } 
  248.                     fd2 = open("/tmp/youdonotknowfile"
  249.                             O_WRONLY|O_CREAT|O_TRUNC,0644); 
  250.                     dup2(fd2, 1); 
  251.                     execvp(arg[0], arg); 
  252.                     exit(0); 
  253.                 } 
  254.                 if (waitpid(pid2, &status2, 0) == -1) 
  255.                     printf("wait for child process error\n"); 
  256.                 if ( !(find_command(argnext[0])) ) { 
  257.                     printf("%s : command not found\n",argnext[0]); 
  258.                     exit(0); 
  259.                 } 
  260.                 fd2 = open("/tmp/youdonotknowfile",O_RDONLY); 
  261.                 dup2(fd2,0); 
  262.                 execvp (argnext[0],argnext); 
  263.                 if ( remove("/tmp/youdonotknowfile") ) 
  264.                     printf("remove error\n"); 
  265.                 exit(0); 
  266.             } 
  267.             break
  268.         default
  269.             break
  270.     } 
  271.     /* 若命令中有&,表示后台执行,父进程直接返回不等待子进程结束 */ 
  272.     if ( background == 1 ) { 
  273.         printf("[process id %d]\n",pid); 
  274.         return ; 
  275.     } 
  276.     /* 父进程等待子进程结束 */ 
  277.     if (waitpid (pid, &status,0) == -1) 
  278.         printf("wait for child process error\n"); 
  279.   
  280. /* 查找命令中的可执行程序 */ 
  281. int find_command (char *command) 
  282.     DIR*             dp; 
  283.     struct dirent*   dirp; 
  284.     char *path[] = { "./""/bin""/usr/bin", NULL}; 
  285.     /* 使当前目录下的程序可以被运行,如命令"./fork"可以被正确解释和执行 */ 
  286.     if( strncmp(command,"./",2) == 0 ) 
  287.         command = command + 2; 
  288.     /* 分别在当前目录、/bin和/usr/bin目录查找要可执行程序 */ 
  289.     int i = 0; 
  290.     while (path[i] != NULL) { 
  291.         if ( (dp = opendir(path[i]) ) == NULL) 
  292.             printf ("can not open /bin \n"); 
  293.         while ( (dirp = readdir(dp)) != NULL) { 
  294.             if (strcmp(dirp->d_name,command) == 0) { 
  295.                 closedir(dp); 
  296.                 return 1; 
  297.             } 
  298.         } 
  299.         closedir (dp); 
  300.         i++; 
  301.     } 
  302.     return 0; 

 下面这段代码是我自己写的,实现了信号和一部分内部命令如cd,kill

 

  1. /********************************************************** 
  2. 在使用输入输出重定向时,需将特殊符号用空格隔开,默认管道与输入重定向和输出重定向不能兼容 
  3. 实例命令: 
  4. ls 
  5. ls & 
  6. ls -l 
  7. ls > in 
  8. cat < in > out 
  9. ls | cat 
  10. cd .. 
  11. cd / 
  12. kill -9 pid 
  13. ***********************************************************/ 
  14. #include <stdio.h> 
  15. #include <stdlib.h> 
  16. #include <string.h> 
  17. #include <unistd.h> 
  18. #include <dirent.h> 
  19. #include <pwd.h> 
  20. #include <grp.h> 
  21. #include <time.h> 
  22. #include <sys/types.h> 
  23. #include <sys/stat.h> 
  24. #include <sys/types.h> 
  25. #include <dirent.h> 
  26. #include <fcntl.h> 
  27. #include <signal.h> 
  28. #define M 1024 
  29.  
  30. void intHandler()//对于ctrl-c的处理 
  31.     printf("\n"); 
  32.  
  33. int main() 
  34.     int i,j,n; 
  35.     int flag_back,flag_in,flag_out,flag_pipe,pid,fd_in,fd_out,status,pid2,status2,fd2;//定义标志变量和文件描述符:后台,输入,输出,管道,定义进程状态 
  36.     char command[M],path[M],*usr,*com[M],*buf,outfile[M],infile[M],*com2[M]; 
  37.     while(1) 
  38.     { 
  39.         signal(SIGINT,intHandler);//为ctrl-c 
  40.         if((usr=getlogin()) == NULL)//获取当前用户名 
  41.         { 
  42.             exit(0); 
  43.         } 
  44.         printf("%s:",usr); 
  45.  
  46.         if(getcwd(path,sizeof(path)-1) == NULL)//获得现有执行路径 
  47.         { 
  48.             exit(0); 
  49.         } 
  50.         printf("%s",path); 
  51.         printf(">"); 
  52.         memset(command,0,sizeof(command));//初始化各变量 
  53.         memset(com,0,sizeof(com)); 
  54.         memset(com2,0,sizeof(com2)); 
  55.         flag_back=0; 
  56.         flag_in=0; 
  57.         flag_out=0; 
  58.         flag_pipe=0; 
  59.         n=0; 
  60.  
  61.         gets(command);//命令获取 
  62.  
  63.         buf=strtok(command," ");//把命令分解,获取各个参数 
  64.         while( buf!= NULL ) 
  65.         { 
  66.             com[n]=buf; 
  67.             n++; 
  68.             buf=strtok(NULL," "); 
  69.         } 
  70.  
  71.         if (!strcmp(com[0],"cd"))//处理内部命令cd 
  72.         { 
  73.             if (n != 1) 
  74.             { 
  75.                 chdir(com[1]); 
  76.             } 
  77.         } 
  78.         else if (!strcmp(com[0],"kill"))//处理内部命令kill,可以实现kill -9 pid类似命令 
  79.         { 
  80.             kill(atoi(com[2]),atoi(com[1]+1)); 
  81.         } 
  82.     else if (!strcmp(command,"exit")||!strcmp(command,"logout"))//查看是否为推出命令 
  83.         { 
  84.             break
  85.         } 
  86.         else if (!strcmp(command,""))//为空继续等待输入 
  87.         { 
  88.             continue
  89.         } 
  90.         else 
  91.         { 
  92.             for ( i = 0; i < n; i++) 
  93.             { 
  94.                 if (!strcmp(com[i],"&"))//后台标志 
  95.                 { 
  96.                     flag_back=1; 
  97.                     for ( j = i; j < n-1; j++) 
  98.                     { 
  99.                         com[j]=com[j+1]; 
  100.                     } 
  101.                     com[n-1]=NULL; 
  102.                     n--; 
  103.                     i--; 
  104.                 } 
  105.                 else if (!strcmp(com[i],">"))//输出重定向 
  106.                 { 
  107.                     flag_out=1; 
  108.                     strcpy(outfile,com[i+1]); 
  109.                     for ( j = i; j < n-2; j++) 
  110.                     { 
  111.                         com[j]=com[j+2]; 
  112.                     } 
  113.                     com[n-2]=NULL; 
  114.                     n-=2; 
  115.                     i--; 
  116.                 } 
  117.                 else if (!strcmp(com[i],"<"))//输入重定向 
  118.                 { 
  119.                     flag_in=1; 
  120.                     strcpy(infile,com[i+1]); 
  121.                     for ( j = i; j < n-2; j++) 
  122.                     { 
  123.                         com[j]=com[j+2]; 
  124.                     } 
  125.                     com[n-2]=NULL; 
  126.                     n-=2; 
  127.                     i--; 
  128.                 } 
  129.                 else if (!strcmp(com[i],"|"))//管道 
  130.                 { 
  131.                     flag_pipe=1; 
  132.                     for ( j = 0; j < i; j++) 
  133.                     { 
  134.                         com2[j]=com[j]; 
  135.                     } 
  136.                     com2[i]=NULL; 
  137.                     for ( j = 0; j < n-i-1; j++) 
  138.                     { 
  139.                         com[j]=com[j+i+1]; 
  140.                     } 
  141.                     com[n-i-1]=NULL; 
  142.                     break
  143.                 } 
  144.             } 
  145.             if ( (pid = fork()) < 0 )//建立子进程 
  146.             { 
  147.                 printf("fork error\n"); 
  148.                 return
  149.             } 
  150.             if (!pid) 
  151.             { 
  152.                 if (flag_out) 
  153.                 { 
  154.                     fd_out = open(outfile,O_RDWR|O_CREAT|O_TRUNC,0644);//输出重定向 
  155.                     dup2(fd_out,1); 
  156.                 } 
  157.                 if (flag_in) 
  158.                 { 
  159.                     fd_in = open(infile,O_RDONLY);//输入重定向 
  160.                     dup2(fd_in,0); 
  161.                 } 
  162.                 if (flag_pipe) 
  163.                 { 
  164.                     if ( (pid2 = fork()) < 0 )//管道建立另一个进程 
  165.                     { 
  166.                         printf("fork2 error\n"); 
  167.                         return
  168.                     } 
  169.                     else if (!pid2) 
  170.                     { 
  171.                         fd2 = open("/tmp/wb",O_WRONLY|O_CREAT|O_TRUNC,0644);//为管道建立临时文件 
  172.                         dup2(fd2,1); 
  173.                         execvp(com2[0],com2); 
  174.                         exit(0); 
  175.                     } 
  176.                     if (waitpid(pid2, &status2, 0) == -1) 
  177.                     { 
  178.                         //printf("wait for child process error\n"); 
  179.                     } 
  180.                     fd2 = open("/tmp/wb",O_RDONLY); 
  181.                     dup2(fd2,0); 
  182.                 } 
  183.                 execvp(com[0],com);//执行命令 
  184.                 remove("/tmp/wb"); 
  185.                 exit(0); 
  186.             } 
  187.             else 
  188.             { 
  189.                 if (flag_back) 
  190.                 { 
  191.                     printf("[process id %d]\n",pid);//若为后台程序,则输出进程号 
  192.                     continue
  193.                 } 
  194.                 else 
  195.                 { 
  196.                     if (waitpid (pid,&status,0) == -1) 
  197.                     { 
  198.                         //printf("wait for child process error\n"); 
  199.                     } 
  200.                 } 
  201.             } 
  202.         } 
  203.     } 
  204.     return 0;