写自己的shell解释器

时间:2023-01-24 19:08:13

http://3270239.blog.51cto.com/3260239/884166

今天研究了简单的shell解释器,里面就虽然只可以解释几条简单的命令,但是看了一些资料,可以调用外部命令,这样的话简单的shell就不简单 了呵呵,我现在还在继续研究,尽量完善,争取写出属于自己的“不简单”的shell解释器。源代码过些时日再发布,就发在此空间,望高手指教,目前为止, 我自己写的shell(minish)可以获得用户名、主机名、路径,包括cd echo help jobs pwd quit等命令,还正在慢慢添加命令。经过一段时间学习,由于鄙人初学,有些命令的加入还是有些难度的,现在把源代码发布,望朋友们指正。

虽然代码短小、功能简单,但毕竟是本人花一段时间,参考一些资料写的,假如转载请注明出处,谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <grp.h>
#include <string.h>
#include <pwd.h>
#include <libgen.h>
#include <sys/types.h>
 
#define CMDNUM 100
 
struct PRO{
        int p_num;
        char p_name[20];
        pid_t p;
        int state;
} process[100];
 
int Analyse(char cmd[],char *arg[],char buf[]);
int func_choice(char cmd[],char *arg[]);
int Help();
int Echo(char *arg[]);
int Cd(char *arg[]);
int Pwd(char *arg[]);
int JobList();
int Record(char cmd[],pid_t p);
int Now=0;
 
int main()
{
        int i;
        char path[1024],*username,host[100],tmp[80];
        struct group *data;
        
        char *arg[100],cmd[100],buf[200];
        data=getgrgid(getgid());
    username=data->gr_name;
    strcat(tmp,username);
        for(i=0;i<100;i++){
                process[i].p_num=0;
                process[i].state=0;
        }//初始化进程记录数组
        //////存入父进程
    printf("\n******Welcome to MiniShell******\n");
    printf("********CopyRight@prince********\n");
    printf("****首次使用请输入命令:help****\n\n");
        process[0].p_num = 1;
        strcpy(process[0].p_name,"minish");
        process[0].p=getpid();
        process[0].state = 1;
        while(1){
            Now = 0;
        if(gethostname(host, 99) == -1) {
            strcpy(host, "localhost");
        }
/*        if(!getcwd(path, 99)) {
            strcpy(path, "unknown");
        } else {
            if(strcmp(path, "/")!= 0)
                strcpy(path, basename(path));
        } */
        if( getcwd(path,1024) == NULL)
              printf("获取路径失败!\n");
        if(strcmp(username,"root")==0)//判断是否为超级用户
            printf("%s@%s:[%s]# ",username,host,path);
        else printf("%s@%s:[%s]$ ",username,host,path);
        if( (fgets(buf,200,stdin)!=NULL) && (*buf != '\n') ){
                buf[strlen(buf)-1] = '\0';
            if(buf[strlen(buf)-2] == '&') Now=1;
            if( !strcmp(buf,"quit") || !strcmp(buf,"exit") || !strcmp(buf,"bye"))
                    return 0;
            Analyse(cmd,arg,buf);
                func_choice(cmd,arg);
         }
 
       }
       return 0;
}

//命令解析
int Analyse(char cmd[],char *arg[],char str[])
{
        int i=0;
        char *p=NULL;
        while( (p = strsep(&str," ")) != NULL)
        {
                if(i==0)
                        strcpy(cmd,p);
                arg[i++]=p;
        }
        if( !strcmp(arg[i-1],"&"))
        {
                arg[i-1] = '\0';
                Now=1;
        }
        else
                arg[i]=NULL;
        return 0;
}

/*根据输入指令执行相应程序*/
int func_choice(char cmd[],char *arg[])
{
 
//        int i;
        pid_t pid;
        //内部命令
        if( !strcmp(cmd,"help"))
                Help();
        else if( !strcmp(cmd,"echo"))
                Echo(arg);
        else if( !strcmp(cmd,"environ"))
                Environ();
        else if( !strcmp(cmd,"cd"))
                Cd(arg);
        else if( !strcmp(cmd,"jobs"))
                JobList();
        else if(!strcmp(cmd,"pwd"))
            Pwd(arg);
        else//外部命令  
        {
                pid = fork();
                if( pid > 0)
                {
                        Record(cmd,pid);
                }
                if( pid < 0 )
                {
                        printf("fork error\n");
                }
                if(pid == 0)
                {
                         if( (execvp(cmd,arg)) < 0 )
                                         printf(" 文件或目录不存在!\n");
                         else
                         {
                                Record(cmd,pid);
 
                         }
                }
        }
 
        if(Now)
                 waitpid(pid,0,WNOHANG);
        else
                waitpid(pid,0,0);
        return 0;
}

//cd:修改当前的工作目录到另一个目录
int Cd(char *arg[])
{
        if( chdir(arg[1]))
            printf("目录不存在!");
        return 0;
}

//pwd:显示当前的所在的工作目录
int Pwd(char *arg[])
{
    char path[1024];
    if( getcwd(path,1024) == NULL)
                printf("获取路径失败!\n");
                printf("**%s**\n",path);
        return 0;
}

//help
int Help()
{
 
       printf("\n\n\n\t*****************************************************\n");
       printf("\t            Welcome to The MiniShell              \n");
       printf("\t-----------------------------------------------------\n");
       printf("\t欢迎使用简易版Shell程序,本程序具备以下功能:                  \n");
       printf("\t       cd:     修改当前的工作目录到另一个目录                  \n");
       printf("\t      pwd:     显示当前的所在的工作目录                  \n");
       printf("\t     echo:     显示echo后的内容且换行                         \n");
       printf("\t     help:     简要介绍Shell的使用方法以及功能                   \n");
       printf("\t     jobs:     输出当前Shell下都一系列子进程                  \n");
       printf("\t     quit:     退出Shell                                \n");
       printf("\t------------------------------------------------------\n");
       printf("\t                               制作时间:2012年5月20日\n");
       printf("\t                               版权所有:      prince \n");
       printf("\t*****************************************************\n\n\n");
       return 0;
}


//Echo:显示echo后的内容且换行
int Echo(char *arg[])
{
         int i=1;
         while(arg[i] != NULL)
        {
                printf("%s ",arg[i++]);
        }
        printf("\n");
        return 0;
}

//env
int Environ()
{
         if( (execl("/bin/env","env",(char *)0)) < 0 )//功能ENV实现
                printf("execl error\n");
        return 0;
}

//Jobs:输出当前Shell下都一系列子进程
int JobList()
{
        int i;
        printf("PID\t进程\t状态\n");
        for(i=0;i<100;i++)
        {
                if(process[i].state == 1){
                        printf("%d\t%s\t",process[i].p,process[i].p_name);
                        printf("RUNNING\n");
                }
        }
        return 0;
}

//记录
int Record(char cmd[],pid_t p)
{
        int i;
 
        for(i=0;i<100;i++)
        {
                if(process[i].state != 1)
                {
                        strcpy(process[i].p_name,cmd);
                        process[i].state = 1;
                        if(p>0) process[i].p = p;
                        break;
                }
        }
        return 0;
}