【Linux小项目】实现自己的bash

0. bash原理介绍

bash实际上就是一个负责解析输入字符串工具.

我们需要做的事是这些:

  1. 手动分割出输入的字符串
  2. 判断哪些变量是内建命令(自己执行),哪些命令是普通命令(创建子进程执行)
  3. 实现的功能有: echo export cd 常规指令 输入、输出流重定向
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>

#define HOST_NAME "hecs-225896"
#define LINE_SIZE 128
#define DELIM " "
#define SHEEL_COMMAND 0
#define NORMAL_COMMAND 1
#define IN_RESTREAM 0
#define OUT_RESTREAM 1
#define APPEND_RESTREAM 2 
#define NONE 0

char pwd[LINE_SIZE];
char command[LINE_SIZE];
char* _argv[LINE_SIZE];
char myenv[LINE_SIZE];
int lastcode;
char * filename;
int restream = NONE;
int stream = 0;


char * getpwd()
{
    return getcwd(pwd,sizeof(pwd));
}
char* getusr()
{
    return getenv("USER");
}
void interactive()
{
    char symbol;
    if(!strcmp(getenv("USER"),"root"))
        symbol='#';
    else
        symbol='$'; 
    printf("%s@"HOST_NAME":""%s""%c ",getusr(),getpwd(),symbol);
    fgets(command,sizeof(command)-1,stdin);
    //消除'n'
    command[strlen(command)-1]='';
    // printf("%s",command);
}
int split()
{
    for(int i=0;command[i];i++)
    {
        if(command[i]=='>')  //写入重定向
        {
            
            command[i++]='';
            restream=OUT_RESTREAM;
            if(command[i]=='>') //追加重定向
            {
                restream=APPEND_RESTREAM;
                command[i++]='';
                while(command[i]==' ')i++;
                filename=command+i;
                printf("filename:%sn",filename);
                stream=open(filename,O_CREAT|O_APPEND,0666);
            }
            else
            {
                while(command[i]==' ')i++;
                filename=command+i;
                printf("filename:%sn",filename);
                stream=open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
            }
            break;

        }
        else if(command[i]=='<')
        {
            restream=IN_RESTREAM;
            command[i++]='';
            while(command[i]==' ')i++;
            filename=command+i;
            printf("filename:%sn",filename);
            stream=open(filename,O_RDONLY);
            break;
        }
    }
    int _argc=0;
    _argv[_argc++]=strtok(command,DELIM);
    while(_argv[_argc]=strtok(NULL,DELIM))
    {
        _argc++;
    }
    _argv[_argc]=NULL;
    return _argc;
}
int JudgeCommand()
{
    if(!strcmp(_argv[0],"cd"))
    {
        return SHEEL_COMMAND;
    }
    else if(!strcmp(_argv[0],"echo"))
    {
        return SHEEL_COMMAND;
    }
    else if(!strcmp(_argv[0],"export"))
    {
        return SHEEL_COMMAND;
    }
    return NORMAL_COMMAND;
}
int execute_NormalCommand()
{
    
    pid_t id=fork();
    if(id<0)
    {
        perror("fork faildn");
        return 1;
    }
    else if(id==0)
    {
        if(restream == OUT_RESTREAM || restream == APPEND_RESTREAM )
        {
            dup2(stream,1);
        }
        else if(restream == IN_RESTREAM)
        {
            dup2(stream,0);
        }
        execvp(_argv[0],_argv);
        exit(2);
    }
    else if(id>0)
    {
        int status=0;
        pid_t wid=waitpid(id,&status,0);
        if(wid==id)
            lastcode = WEXITSTATUS(status);
    }
}
int execute_ShellCommand(int argc)
{
    if(argc>=2&&!strcmp(_argv[0],"cd"))
    {
        int rev=chdir(_argv[1]);
        if(rev!=0)
        {
            perror("return faild");
        }
    }
    else if(argc>=2&&!strcmp(_argv[0],"echo"))
    {
        if(_argv[1][0]=='$')
        {
            printf("%c",_argv[1][0]);
            char * env=getenv(_argv[1]+1);
            if(env)printf("%sn",env);
        }
        else if(!strcmp(_argv[1],"?"))
        {
            printf("%dn",lastcode);
            lastcode=0;
        }
        else
            printf("%sn",_argv[1]);
    }
    else if(argc>=2&&!strcmp(_argv[0],"export"))
    {
        strcpy(myenv,_argv[1]);
        putenv(_argv[1]);
    }
    
    
}
void BuildCommand(int *_argc)
{
    if(!strcmp(_argv[0],"ls"))
    {
        _argv[(*_argc)++]="--color";
        _argv[*_argc]=NULL;
    }
}

int main()
{
    while(1)
    {
        interactive();
        int argc=split();
        if(argc==0)continue;
        // for(int i=0;i<argc;i++)printf("%sn",_argv[i]);
        int RunFlag=JudgeCommand();
        BuildCommand(&argc);
        if(RunFlag==NORMAL_COMMAND)
        {
            execute_NormalCommand();
        }
        else{
            execute_ShellCommand(argc);
        }
    }
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>