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

0. bash原理介绍

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

我们需要做的事是这些:

  1. 手动分割出输入的字符串
  2. 判断哪些变量是内建命令(自己执行),哪些命令是普通命令(创建子进程执行)
  3. 实现的功能有: echo export cd 常规指令 输入、输出流重定向
cpp 复制代码
#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);
        }
    }
}
相关推荐
chlk1239 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑9 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件10 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号19 小时前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash1 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI1 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行2 天前
Linux和window共享文件夹
linux
木心月转码ing2 天前
WSL+Cpp开发环境配置
linux
崔小汤呀3 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应3 天前
vi编辑器使用
linux·后端·操作系统