这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【转载】模拟实现命令行解释器shell--from森

共1条 1/1 1 跳转至

【转载】模拟实现命令行解释器shell--from森

工程师
2024-12-21 13:11:33     打赏

shell本质就是一个进程,它提供了一个用户界面,用于接收用户输入的命令,并将这些命令解释成操作系统能够理解和执行的操作。

它充当了用户和操作系统内核之间的中介。例如,在 Linux 系统中,当用户在终端输入ls命令时,shell 会解释这个命令,告诉操作

系统去列出当前目录下的文件和目录信息。

下面是模拟实现shell的基本代码:

#include <iostream>

#include <string>

#include <cstring>

#include <cstdio>

#include <cstdlib>

#include <unistd.h>

#include <sys/types.h>

#include <sys/wait.h>

using namespace std;

 

const int basesize = 1024;

const int argvnum = 64;

const int envnum = 64;

 

//全局的命令行参数表

char *gargv[argvnum];

int gargc = 0;

 

//我自己的环境变量

char *genv[envnum];

 

//全局变量,用来表示退出结果

int lastcode = 0;

 

// 全局的工作路径

char pwd[basesize];

char pwdenv[basesize * 2];

 

string GetName()

{

    string name = getenv("USER");

    return name.empty() ? "None" : name;

}

 

string GetHostName()

{

    char hostname[basesize];

    gethostname(hostname, sizeof(hostname));

    ;

    return gethostname(hostname, sizeof(hostname)) != 0 ? "None" : hostname;

}

 

string GetPwd()

{

    // getcwd获取当前工作路径

    if (nullptr == getcwd(pwd, sizeof(pwd)))

        return "None";

    // 讲获取的当前路径输入到pwdenv

    snprintf(pwdenv, sizeof(pwdenv), "PWD=%s", pwd);

    // 导入环境变量

    putenv(pwdenv);

    return pwd;

    // string pwd = getenv("PWD");

    // return pwd.empty() ? "None" : pwd;

}

 

string LastDir()

{

    string curr = GetPwd();

    if(curr == "/" || curr == "None") return curr;

    // /home/xzl/xxx

    size_t pos = curr.rfind("/");

    if(pos == std::string::npos) return curr;

    return curr.substr(pos+1);

}

 

string MakeCommandLine()

{

    char Command_Line[basesize];

    snprintf(Command_Line, basesize, "[%s@%s %s]#",\

     GetName().c_str(), GetHostName().c_str(), LastDir().c_str());

    return Command_Line;

}

 

// 打印命令行提示符

void PrintCommandLine()

{

    printf("%s", MakeCommandLine().c_str());

    fflush(stdout);

}

// 获取用户命令

bool GetCommandLine(char command_buffer[])

{

    // 获取字符串

    char *result = fgets(command_buffer, basesize, stdin);

    if (!result)

    {

        return false;

    }

    command_buffer[strlen(command_buffer) - 1] = 0;

    if (strlen(command_buffer) == 0)

        return false;

    return true;

}

 

//  分析命令

void ParseCommandLine(char command_buffer[])

{

    memset(gargv, 0, sizeof(gargc));

    gargc = 0;

    const char *seq = " ";

    gargv[gargc++] = strtok(command_buffer, seq);

    while (gargv[gargc++] = strtok(nullptr, seq))

        ;

    gargc--;

}

 

void debug()

{

    printf("argc: %d\n", gargc);

    for (int i = 0; gargv[i]; i++)

    {

        printf("argv[%d]: %s\n", i, gargv[i]);

    }

}

 

//执行命令

bool ExecuteCommand()

{

    pid_t id = fork();

    if (id < 0)

        return false;

    else if (id == 0)

    {

        // 子进程

        //执行命令

        execvpe(gargv[0], gargv,genv);

        //退出

        exit(1);

    }

    int status = 0;

    pid_t rid = waitpid(id, &status, 0);

    if (rid > 0)

    {

        if(WIFEXITED(status))

        {

            lastcode = WEXITSTATUS(status);

        }

        else//表示代码异常退出

        {

            lastcode = 100;

        }

        return true;

 

    }

    return false;

}

 

void AddEnv(const char *item)

{

    int index = 0;

    while(genv[index])

    {

        index++;

    }

    genv[index] = (char*)malloc(strlen(item)+1);

    strncpy(genv[index],item,strlen(item)+1);

    index++;

    genv[index] = nullptr;

}

 

//在shell中

//有些命令,必须由子进程执行

//有些命令,不能由子进程执行,要由shell自己执行 -----内建命令 built command

bool CheckAndExecBuiltCommand()

{

    //不能让子进程进行,因为子进程退出就结束了,并不能影响下一个进程的工作路径

    if (strcmp(gargv[0], "cd") == 0)

    {

        if (gargc == 2)

        {

            chdir(gargv[1]);

            lastcode = 0;

        }

        else

        {

            lastcode = 1;

        }

        return true;

    }

    else if(strcmp(gargv[0],"export")==0)

    {

        if(gargc == 2)

        {

            AddEnv(gargv[1]);

            lastcode = 0;

        }

        else

        {

            lastcode = 2;

        }

    }

    else if(strcmp(gargv[0],"env") == 0)

    {

        for(int i = 0 ;genv[i];i++)

        {

            printf("%s\n",genv[i]);

        }

        lastcode = 0;

        return true;

    }

    else if(strcmp(gargv[0],"echo") == 0)

    {

        if(gargc == 2)

        {

            //echo $?

            //echo $PATH

            //echo hello

            if(gargv[1][0] == '$')

            {

                if(gargv[1][1] == '?')

                {

                    printf("%d\n",lastcode);

                    lastcode = 0;

                }

            }

            else

            {

                printf("%s\n",gargv[1]);

                lastcode = 0;

            }

        }

        else

        {

            lastcode = 3;

        }

        return true;

    }

    return false;

}

 

//作为一个shell,获取环境变量应该从系统环境变量获取

//今天外面做不到就直接从父进程shell中获取环境变量

void InitEnv()

{

    extern char **environ;

    int index = 0;

    while (environ[index])

    {

        genv[index] = (char*)malloc(strlen(environ[index])+1);

        strncpy(genv[index],environ[index],strlen(environ[index]));

        index++;

    }

    genv[index] = nullptr;

    

}

 

int main()

{

    //初始化环境变量表

    InitEnv();

    char command_buffer[basesize];

    while (true)

    {

        // 打印命令行提示符

        PrintCommandLine();

        // 获取用户命令

        if (!GetCommandLine(command_buffer))

        {

            continue;

        }

        // printf("%s\n", command_buffer);

        //  分析命令

        ParseCommandLine(command_buffer);

 

        // 判断是不是内建命令

        if (CheckAndExecBuiltCommand())

        {

            continue;

        }

        // debug();

        // 执行命令

        ExecuteCommand();

    }

    return 0;

}

来源: 整理文章为传播相关技术,网络版权归原作者所有,如有侵权,请联系删除。




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]