自己动手制作一个简易的shell

来源:互联网 发布:随身带了淘宝去异界 编辑:程序博客网 时间:2024/06/05 01:17

本人最近在看《Unix环境高级编层》,其上面的程序清单1-5的程序介绍了如何制作一个shell,而后本人又做了一点改进,改进的地方如下:

1.为了方便查看,删除了原来的err_sys()函数和其自定义的"apue.h"这个头文件!

2.增加了对于命令选项处理的功能,但是不是很强大,目前只能处理单个参数!


本人写的代码如下:

#include<stdio.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#include<stdlib.h>#define MAXLINE 2048int main(int argc,char *argv[]){    char buf[MAXLINE];    char com[MAXLINE];    char para[MAXLINE];    int i=0,p_l=0,c_l=0;    pid_t pid;          //存储子进程的id    int status;//waitpid函数返回的子进程的状态    printf("%%");       //输出提示符%    while((fgets(buf,MAXLINE,stdin)) != NULL)    {if(buf[strlen(buf)-1] == '\n')    buf[strlen(buf)-1]='\0';//重新设置命令和参数i=0;p_l=0;memset(com,0,MAXLINE);c_l=0;memset(para,0,MAXLINE);        printf("buf:%s\n",buf);while(buf[i] == ' ')//将命令开始的空格都给忽略掉    i++;while(buf[i] != ' ')//读取命令{    com[c_l]=buf[i];    i++;    c_l++;}while(buf[i] == ' ')//将命令和参数之间的空格都给忽略掉    i++;while(buf[i] != '\0')//读取参数{   if(buf[i] != ' ')    //将参数中间的空格忽略掉   {      para[p_l]=buf[i];       p_l++;   }   i++;}                printf("com:%s para:%s\n",com,para);        pid=fork();//创建子进程if(pid < 0)//创建子进程出错{    perror("fork error");}else if(pid == 0)//子进程的执行部分{    if(para[0] != 0)execlp(com,com,para,(char *)0);    execlp(com,com,(char *)0);    perror("execlp error");  //如果execlp()函数无法执行,则输出错误信息!    exit(127);}if((pid = waitpid(pid,&status,0)) < 0)//父进程等待子进程结束{    perror("waitpid error");}memset(buf,0,MAXLINE);//重新设置buf的缓存空间printf("%%");    }    return 0;}

这个程序的思路是这样的,

数据部分,我创建了三个char数组,buf,com,para,分别用来存储读取到的字符串,分析到的命令,分析到的参数!三个int型变量,i,p_l,c_l。分别用来给buf、para、com计数!

执行部分,首先通过fgets()函数将命令读取到buf这个char数组中。然后将com和para数组全部初始化为0。然后,就开始分析命令。

分析过程如下:

    首先,将命令开始的空格全部忽略。第二,从第一个非空格部分到下一个空格为命令部分,存储到com数组中!第三,读取完命令之后,剩下的部分全部视为参数了,并且忽略掉其中的空格,存储到para数组中!

   Ok,这样,分析就分析完了,开始执行!这里的思路主要就是当前这个进程创建一个子进程,然后将上面分析到的命令和参数传递给execlp()函数,让子进程执行execlp()函数,execlp函数的主要功能是将其传入的命令替换掉进程中的程序部分,这样子进程执行的就是我们给execlp()函数传递命令和参数了!

    这里,我想讲一下个人对于fork()这个函数的理解,如若有误,还请多多指出!

   

   如上图所示,个人认为fork函数是一个分水岭,在这里开始创建一个子进程,子进程复制了父进程的数据和程序,这时就有两个进程在执行中间这段代码了,fork()函数给父进程返回的是子进程的pid(正常情况下,如果出错,返回一个小于0的值),给子进程返回的pid是0。所以父进程什么也没执行,直接执行到了waitpid()那里,而子进程呢,由于其pid是0,所以执行了if(pid==0)这个条件下的代码!

   在if(pid == 0)中,子进程执行了execlp()函数,这个函数就是将进程中的代码全部替换成其传入命令的代码,比如,如果我们给execlp传入的是ls命令,那么这个子进程执行的完全就是ls命令的代码。


   通过这样,我们就成功的实现了一个极其简单的shell!以下是结果的截图:

   

  当然,问题还是很多的,比如执行cd ..就不行,输出变量也不行!

 


  最后,俺想说一句,俺能力有限,水平有限,做出这个程序实在是为了自娱自乐,有很多不足的地方,还请各位大神轻拍啊!

0 0
原创粉丝点击