【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);
        }
    }
}
相关推荐
程序员yt40 分钟前
双非一本电子信息专业自学嵌入式,学完 Linux 后咋走?单片机 & FreeRTOS 要补吗?
linux·运维·单片机
安於宿命5 小时前
【Linux】进程间通信——进程池
linux·c++
新兴ICT项目支撑6 小时前
天翼云910B部署DeepSeek蒸馏70B LLaMA模型实践总结
linux·运维·服务器·910b·天翼云·deepseek r1
Spike()8 小时前
HaProxy源码安装(Rocky8)
linux·负载均衡
网硕互联的小客服8 小时前
如何提高网站在百度中的权重?
linux·运维·服务器·windows·安全
守望时空339 小时前
Linux内核升级指南
linux·操作系统
Aphelios38010 小时前
Linux 下 VIM 编辑器学习记录:从基础到进阶(上)
java·linux·编辑器·vim
chde2Wang10 小时前
yum下载报错Could not resolve host: mirrorlist.centos.org; Unknown error
linux·运维·centos
zyx没烦恼11 小时前
Linux 进程控制(进程创建,进程等待)
linux·运维·服务器
linux开发之路11 小时前
C++Linux进阶项目分析-仿写Redis之Qedis
linux·c++·redis·多线程·后端开发