【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]='\0';
    // printf("%s",command);
}
int split()
{
    for(int i=0;command[i];i++)
    {
        if(command[i]=='>')  //写入重定向
        {
            
            command[i++]='\0';
            restream=OUT_RESTREAM;
            if(command[i]=='>') //追加重定向
            {
                restream=APPEND_RESTREAM;
                command[i++]='\0';
                while(command[i]==' ')i++;
                filename=command+i;
                printf("filename:%s\n",filename);
                stream=open(filename,O_CREAT|O_APPEND,0666);
            }
            else
            {
                while(command[i]==' ')i++;
                filename=command+i;
                printf("filename:%s\n",filename);
                stream=open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
            }
            break;

        }
        else if(command[i]=='<')
        {
            restream=IN_RESTREAM;
            command[i++]='\0';
            while(command[i]==' ')i++;
            filename=command+i;
            printf("filename:%s\n",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 faild\n");
        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("%s\n",env);
        }
        else if(!strcmp(_argv[1],"?"))
        {
            printf("%d\n",lastcode);
            lastcode=0;
        }
        else
            printf("%s\n",_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("%s\n",_argv[i]);
        int RunFlag=JudgeCommand();
        BuildCommand(&argc);
        if(RunFlag==NORMAL_COMMAND)
        {
            execute_NormalCommand();
        }
        else{
            execute_ShellCommand(argc);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ppeua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值