现在的位置: 首页 > 综合 > 正文

编写shell(二)

2013年10月03日 ⁄ 综合 ⁄ 共 3368字 ⁄ 字号 评论关闭

编写shell

刺猬@http://blog.csdn.net/littlehedgehog

接着来写shell,今天来加上我们的条件判断语句if。

为了处理if的逻辑判断,我们这里把代码区域做个划分。如下举例所示:

  1. who   
  2. ls -al 
  3. if  diff file1  file2   
  4. ---------------以上是中立区 netral
  5. then 
  6. ---------------want_then区(经过if条件判断以后 可能是want_then 或者 want_else)
  7. echo different 
  8. ---------------then_block区
  9. else
  10. ---------------want_else区
  11. echo same 
  12. ---------------else_block区
  13. fi
  14. ---------------fi是if倒着写 表示if结束了 那么我们又进入中立区了

这里有几点需要注意的是:
1、经过if判断后,if后面的条件有可能成立有可能不成立,所以我们可能想要then(want_then),也可能想要else(want_else)。
2、假如是want_else ,那么执行then后面的命令,我们以为要执行else,所以这些命令不予执行,所处状态还是want_else
3、限于程序的简陋,很多功能未实现,比如if多条件判断,比如一行多命令执行等等。

现在那就看代码吧! 注意原书中没有考虑else,这里已经添上else判断。代码中我注释很多,算是对书上代码的一个补充了。

  1. #include <stdio.h>
  2. #include <string.h>
  3. //#define DEBUG
  4. extern execute(char **);
  5. enum states {NEUTRAL,WANT_THEN,THEN_BLOCK,WANT_ELSE,ELSE_BLOCK};
  6. enum result {SUCCESS,FAIL};
  7. static int if_state=NEUTRAL;
  8. static int if_result=SUCCESS;
  9. static int pro_state=0;
  10. void die(char *err)
  11. {
  12.     fprintf(stderr,"fatal error :%s/n",err);
  13.     exit(1);
  14. }
  15. int syn_err(char *err)
  16. {
  17.     if_state=NEUTRAL;   //出事前我们需要重新设置中立状态
  18.     fprintf(stderr,"sysntax error : %s/n",err);
  19.     return -1;
  20. }
  21. int is_ctlcmd(char *str)
  22. {
  23.     if(strcmp(str,"if")==0||strcmp(str,"then")==0||strcmp(str,"else")==0||strcmp(str,"fi")==0)
  24.         return 1;
  25.     return 0;
  26. }
  27. /* 这个函数主要处理语法分析(目前仅支持if) */
  28. int do_ctlcmd(char **argv)
  29. {
  30.     int ret=-1;
  31.     char *cmd=argv[0];
  32.     if(strcmp(cmd,"if")==0)         //如果当前命令是if
  33.     {
  34.         if(if_state!=NEUTRAL)       //暂时不支持命令嵌套
  35.         {
  36.             ret=-1;
  37.             syn_err("if unexpected ");  
  38.         }
  39.         else
  40.         {
  41. #ifndef DEBUG
  42.             pro_state=execute(argv+1);      //执行if后面的语句 比如 if diff file1 file2
  43. #else
  44.             pro_state=0;
  45. #endif          
  46.             if_state=pro_state?WANT_ELSE:WANT_THEN; //注意是0为成功 非0失败
  47.             if_result=pro_state?FAIL:SUCCESS;   
  48.             
  49.             ret=0;
  50.         }       
  51.     }
  52.     else if (strcmp(cmd,"then")==0)         //如果当前命令是then  单独一行
  53.     {
  54.         if(if_state==WANT_THEN)             
  55.         {if_state=THEN_BLOCK;ret=0;}
  56.         else if(if_state!=WANT_ELSE)        //当前命令是then 那么state要么是WANT_THEN 要么是WANT_ELSE    
  57.             syn_err("then unexpected ");
  58.     }
  59.     else if (strcmp(cmd,"else")==0)         //单独一行 
  60.     {
  61.         if(if_state==WANT_ELSE)
  62.         {if_state==ELSE_BLOCK;ret=0;}
  63.         else if(if_state!=THEN_BLOCK)       //既然进入else 那么要么是THEN_BLOCK 要么是WANT_ELSE
  64.             syn_err("syntax error ");
  65.     }
  66.     else if (strcmp(cmd,"fi")==0)
  67.     {
  68.         if(if_state==NEUTRAL)
  69.             syn_err("syntax error :");
  70.         if_state==NEUTRAL;
  71.         ret=0;
  72.     }
  73.     else
  74.         die("process error! not your problem");
  75.     return ret;
  76. }
  77. /* 检查当前 是否能执行语句 
  78.  * 返回值 1:能执行 0:不能执行
  79.  */
  80. int check_execute()
  81. {
  82.     int ret=1;
  83.     switch(if_state)
  84.     {
  85.         case WANT_THEN:
  86.         case WANT_ELSE:
  87.             break;
  88.         case THEN_BLOCK:
  89.             if(if_result==FAIL)     //进入了then 但是if中间的判断是 if(...) 为假 所以我们不能执行THEN_BLOCK
  90.                 ret=0;
  91.             break;
  92.         case ELSE_BLOCK:
  93.             if (if_result==SUCCESS) //同样 不能执行ELSE_BLOCK 
  94.                 ret=0;
  95.             break;
  96.     }
  97.     return ret;
  98. }
  99. int process(char *argv[])
  100. {
  101.     int ret=0;
  102.     if(!argv[0])
  103.         ret=0;
  104.     else if (is_ctlcmd(argv[0]))    //检查是不是命令 比如if
  105.         ret=do_ctlcmd(argv);
  106.     else if (check_execute())       //检查是否能运行
  107. #ifndef DEBUG
  108.         ret=execute(argv);
  109. #else 
  110.         ret=0;
  111. #endif
  112.     return ret;
  113. }

编译时,将《编写shell(一)》中的代码和此代码一起编译:

gcc -o target shell1.c shell2.c

抱歉!评论已关闭.