编写自己的Shell解释器-5[转]

命令处理

首先是对处于“shell语法规范”中最上层的列表命令的处理。

l         列表命令的处理过程:

依次检查参数数组中的每一个参数,如果是分号(;),那么就认为分号前面的所有参数组成了一个管道命令,调用 do_pipe_cmd() 来执行对管道命令的处理。如果扫描到最后,不再有分号出现,那么把剩下的所有参数作为一个管道命令处理。

代码很简单:

static void do_list_cmd()

{

       int i = 0;

       int j = 0;

       char* p;

       while(argbuf[i]) {

              if(strcmp(argbuf[i], ";") == 0) {//  ;

                     p = argbuf[i];

                     argbuf[i] = 0;

                     do_pipe_cmd(i-j, argbuf+j);

                     argbuf[i] = p;

                     j = ++i;

              } else

                     i++;

       }

       do_pipe_cmd(i-j, argbuf+j);

}


接下来是对管道命令的处理。

管道命令的处理

管道是进程间通信(IPC)的一种形式,关于管道的详细解释在《unix高级环境编程》第14章:进程间通信以及《unix网络编程:第2卷:进程间通信》第4章:管道和FIFO中可以看到。

我们还是来看一个管道的例子:

[root@stevens root]#  echo “hello world”|wc –c |wc –l

在这个例子中,有三个简单命令和两个管道。

第一个命令是 echo “hello world”,它在屏幕上输出 hello world。由于它后面是一个管道,因此,它并不在屏幕上输出结果,而是把它的输出重定向到管道的写入端。

第二个命令是 wc –c,它本来需要指定输入源,由于它前面是一个管道,因此它就从这个管道的读出端读数据。也就是说读到的是 hello worldwc –c 是统计读到的字符数,结果应该是12。由于它后面又出现一个管道,因此这个结果不能输出到屏幕上,而是重定向到第二个管道的写入端。

第三个命令是 wc –l。它同样从第二个管道的读出端读数据,读到的是12,然后它统计读到了几行数据,结果是1行,于是在屏幕上输出的最终结果是1

在这个例子中,第一个命令只有一个“后”管道,第三个命令只有一个“前”管道,而第二个命令既有“前”管道,又有“后”管道。

在我们处理管道命令的do_pipe_cmd()函数中,它的处理过程是:

首先定义两个管道 prefd postfd,它们分别用来保存“前”管道和“后”管道。此外,还有一个变量 prepipe 来指示“前”管道是否有效。

然后依次检查参数数组中每一个参数,如果是管道符号(|),那么就认为管道符号前面所有的参数组成了一个简单命令,并创建一个“后”管道。如果没有“前”管道(管道中第一个简单命令是没有“前”管道的),那么只传递“后”管道来调用do_simple_cmd(),否则,同时传递“前”管道和“后”管道来调用 do_simple_cmd()

执行完以后,用“前”管道来保存当前的“后”管道,并设置“前”管道有效标识prepipe,继续往后扫描。如果扫描到最后,不再有管道符号出现,那么只传递“前”管道来调用do_simple_cmd()

代码如下:

int i = 0, j = 0, prepipe = 0;

int prefd[2], postfd[2];

char* p;

while(argv[i]) {

       if(strcmp(argv[i], "|") == 0) { // pipe

              p = argv[i];

              argv[i] = 0;

              pipe(postfd);         //create the post pipe

              if(prepipe)      

                     do_simple_cmd(i-j, argv+j, prefd, postfd);

              else

                     do_simple_cmd(i-j, argv+j, 0, postfd);

              argv[i] = p;

              prepipe = 1;

              prefd[0] = postfd[0];

              prefd[1] = postfd[1];

              j = ++i;

       } else

              i++;

}

if(prepipe)

       do_simple_cmd(i-j, argv+j, prefd, 0);

else

       do_simple_cmd(i-j, argv+j, 0, 0);

最后,我们分析简单命令的处理过程。

posted @ 2008-12-05 22:32  aoogur  阅读(417)  评论(0编辑  收藏  举报