搓个shell命令行!

目录

写个简单shell

命令行提示符

获取用户命令

分析命令

执行命令

内建命令

代码


写个简单shell

shell(bash)也是一个进程

死循环执行以下操作

  1. 命令行提示符
  2. 获取命令行
  3. 分析命令
  4. 执行命令

命令行提示符

环境变量获取用户,地址

getenv获取环境变量 ,不存在返回空,注意情况

fflush刷新缓冲区

获取用户命令

我们要把用户输入的命令行,当做一个完整的字符串

可以用getline 或者 fgets

这次用fgets,当然getline更简单

用户输入回车,获取的字符串会带\n要处理一下吧

分析命令

用strtok来分割字符串,先分隔成字符串数组

执行命令

让子进程去执行

  1. 执行命令  exec*
  2. 退出   exit(),当走到这肯定没有执行成功,因为程序替换成功就没有exit了

cd命令有问题,因为子进程执行完cd我们退出来是在父进程,还是原来的路径,要改的是父进程的pwd

所以得出有些命令必须由子进程执行,有些命令,要由shell自己执行—内建命令 built command

内建命令

所以要加一个步骤,检查是否是内建命令,是就自己执行,

shell自己执行命令,本质是shell调用自己的函数,内建命令很少差不多占5%

内建命令:cd = chdir  echo  export要修改环境变量的PWD。要我们自己的shell去维护

getcwd 获取当前工作路径

环境变量要shell自己维护

作为一个shell,获取环境变量应该从系统的配置来

我们今天就直接从父shell中获取环境变量

本地变量表  : a=100  这种不能通过环境变量和命令行参数传给子进程,但是可以echo$a所以echo也是内建命令

代码

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<string>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
using namespace std;

#define identif "(•́へ•́☆)*哎哟不错哦" 

int buffermax = 1024;
//输出的缓冲区
char* printbuffer = (char*)malloc(sizeof(char)*buffermax);
//获取输入的缓冲区
char* scanfbuffer = (char*)malloc(sizeof(char)*buffermax);

//命令行参数
int gargc = 0;
char** gargv = (char**)malloc(sizeof(char)*buffermax);

char* getname()
{
    return getenv("USER"); 
}
char* gethostname()
{
    return getenv("HOSTNAME");
}

char* getpwd()
{
    return getenv("PWD");
}
void PrintCommandLine()
{
    //[xjh@hcss-ecs-769a learnclass5--myshell]$
    snprintf(printbuffer,buffermax,"%s@%s %s",getname(),gethostname(),getpwd());
    printf("[%s]%s",printbuffer,identif);
    fflush(stdin);

}

void GetCommandLine()
{
    memset(scanfbuffer,0,buffermax);
    fgets(scanfbuffer,buffermax,stdin);
    //去换行符
    int s = strlen(scanfbuffer);
    scanfbuffer[s-1] = 0;
}

void AnalyseCommandLine()
{
    gargc = 0;
    memset(gargv,0,buffermax);
    //分割命令
    gargv[gargc++] = strtok(scanfbuffer," ");
    while((bool)(gargv[gargc] = strtok(NULL," ")))
    {
        gargc++;
    }
}

void ExeCommandLine()
{
    pid_t id = fork();
    //让子进程去执行命令
    if(id == 0)
    {
        //因为又命令行列表所以使用带v,并且gargv[0]就是地址所以带p我们使用execvp
        int ret = execvp(gargv[0],gargv);

        //由于程序替换走不到exit所以如果程序替换失败了会有返回-1;
        exit(ret);
    }
    //父进程
    int status = 0;
    int rid = waitpid(id,&status,0);
    if(rid > 0)
    {

    }

}

bool BuiitCommandLine()
{
    if(strcmp(gargv[0],"cd")==0)
    {
        if(gargv[1])
        {
        chdir(gargv[1]);
        //环境变量缓冲区
        char* cwd = (char*)malloc(sizeof(char)*buffermax);
        char tmp[buffermax];
        getcwd(tmp,sizeof(tmp));
        snprintf(cwd,buffermax,"PWD=%s",tmp);
        putenv(cwd);
        }
        return true;
    }
    return false;
}


int main()
{
    while(true)
    {
        
        //打印命令行提示符
        PrintCommandLine();
        //获取用户命令
        GetCommandLine();
        if(!strlen(scanfbuffer))
            continue;
        //分析命令
        AnalyseCommandLine();
        //内建命令
        if(BuiitCommandLine())
                continue;
        //执行命令
        ExeCommandLine();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值