Linux:shell原理以及模拟实现

在这里插入图片描述
hello,各位小伙伴,本篇文章跟大家一起学习《Linux:shell原理以及模拟实现》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!

话不多说,开始正题:

模拟实现shell

对于模拟实现shell分这几步走:
由于shell不断读取命令,也就是说可以利用死循环来实现

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
   
   
    while(true)
    {
   
   
        PrintCommandLine(); // 1. 命令行提示符

        GetCommandLine();   // 2. 获取用户命令

        ParseCommandLine(); // 3. 分析命令

        ExecuteCommand();   // 4. 执行命令

    }
    return 0;
}

怎么退出shell,我的做法是直接Ctrl + C!!!

PrintCommandLine()

在这里插入图片描述
对于获取这些信息可以使用系统的接口,其实也可以用环境变量来进行获取getenv()

#include <cstdlib>
#include <cstring>
#include <string>
string GetUserName()
{
   
   
    const char* name = getenv("USER");
    return (name && name[0] != '\0') ? name : "None";  // 检查是否为nullptr并确保非空
}

string GetHostName()
{
   
   
    const char* hostname = getenv("HOSTNAME");
    return (hostname && hostname[0] != '\0') ? hostname : "None";
}

string GetPwd()
{
   
   
    const char* pwd = getenv("PWD");
    return (pwd && pwd[0] != '\0') ? pwd : "None";
}

输出命令行:

const int basesize = 1024;
string MakeCommandLine()
{
   
   
    char line[basesize];
    snprintf(line, basesize, "[%s@%s %s]# ",\
    	GetUserName().c_str(), GetHostName().c_str(), GetPwd().c_str());
}

对于snprintf是将一个字符串格式化输出到另一个字符串中
在这里插入图片描述
为了区别和shell原本的命令行,在这里使用#来替换掉$

以上就将PrintCommandLine差不多写完了:

由于命令行上不带\n,所以要刷新缓冲区就可以使用fflush(stdout)来对显示器进行刷新

void PrintCommandLine()
{
   
   
    printf("%s", MakeCommandLine().c_str());
    fflush(stdout);
}

int main()
{
   
   
    while(true)
    {
   
   
        PrintCommandLine(); // 1. 命令行提示符
    }
    return 0;
}

可以test一下:

while(true)
    {
   
   
        PrintCommandLine(); // 1. 命令行提示符
		printf("%s\n",buffer);
		sleep(1);
    }

GetCommandLine()

要获取用户输入的命令,可以用一个字符串来记录buffer[]

char buffer[basesize];

由于我们并不清楚用户会输入多少个命令选项(ls -l -a……),所以我们并不能使用cin来获取字符串,要把整个用户输入的当作一个字符串,这里我使用fgets()
在这里插入图片描述
从一个文件流里获取字符串:

char *result = fgets(buffer, size, stdin);

因为当用户输入指令错误时会返回打印命令行提示符,所以我们要检测用户是否成功输入,采用bool,因为用户输入完指令之后会按回车,字符串中就会多一个\n,我们要去掉:

bool GetCommandLine(char buffer[], int size) // 2. 获取用户命令
{
   
   
    char *result = fgets(buffer, size, stdin);
    if(!result)
    {
   
   
        return false;
    }
    buffer[strlen(buffer) - 1] = 0; // 将 \n 去掉
    return true;
}

test一下:

int main()
{
   
   
    char buffer[basesize];
    while(true)
    {
   
   
        PrintCommandLine(); // 1. 命令行提示符

        if(!GetCommandLine(buffer, basesize))   // 2. 获取用户命令
        {
   
   
            continue;
        }
        printf("%s\n", buffer);
        // ParseCommandLine(); // 3. 分析命令

        // ExecuteCommand();   // 4. 执行命令

    }

ParseCommandLine()

对于解析命令行,不就是将一个字符串拆成一个一个字符,有多少个字符可以使用整形int来存储,字符可以放在char *数组来存储,这不就是main的参数吗?int argc, char *argv
在这里插入图片描述
我在这里创建2个全局变量int gargc = 0; char *gargv[argvnum];
gargc用来记录多少个字符,gargv用来记录分割好的字符指令
传参:

ParseCommandLine(buffer, strlen(buffer)); // 3. 分析命令

函数实现:

void ParseCommandLine(char buffer[], int len) // 3. 分析命令
{
   
   
    (void)len; // 解除报警
    gargc = 0;
    memset(gargv, 0, sizeof((char*)buffer)); // 为了保证安全,清空历史字符串
    const char *sep = " "; // 作为分割符
    gargv[gargc++] = strtok(buffer, sep);
    while(gargv[gargc++] = strtok(nullptr, sep));
    gargc--;
}

开始前将gargc,gargv重置是为了保证安全

对于strtok可自行了解,实际上就是找到分隔符并将其设置为\0strtok有个设定,你若想从上次记录的位置继续分割,第一个参数必须是nullptr或者NULL

由于gargc的后置++会导致多++一次,所以后续进行--一次

ParseCommandLine进行test:

void debug()
{
   
   
    printf("gargc: %d\n", gargc);
    for(int i = 0; i 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值