当前位置: 首页 > news >正文

【Linux】shell命令行简单解释器


回顾一下,我们前面学习了进程创建,进程终止,进程等待,进程替换,通过这些内容我们可以来进行实现简单的shell命令行解释器!!!下面我们直接来看一看如何去实现shell命令行解释器:

总体分为(整体需要循环哦):

1.输出提示符

2.输入和获取命令

3.fork创建子进程

4.内建命令


  • 输出提示符

这里的提示字符为用户名@主机名 当前路径# 直接打印出来作为提示所用,也可以自己设置成其他的,问题不大

printf("用户名@主机名 当前路径# ");

同时,这里并没有\n,会有缓冲区的问题,类似于我们之前所说的进度条所遇到的问题,在这个地方哦可以用fflush(stdout)刷新缓冲区

  • 输入和获取命令

输入

我们需要获取一行的内容,利用fgets函数获取,同时,可以定义一个lineCommand[NUM]数组

char*s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
assert(s != NULL);

但是打印的时候却多换了一行,这是我们把\n也读取到了,直接进行处理即可,清除最后一个\n

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

获取

输入之后,我们自然需要去进行获取,我们需要分割命令行,这个地方用strtok。把字符串切割成若干个子串:

strtok:第一次直接传递参数,第二次则必须传NULL。且在最终strtok会返回NULL。

  • fork创建进程

利用fork创建子进程,同时父进程需要等待子进程退出返回结果

另外我们还需要选择替换函数execvp:首先替换函数需要先带上v,可将所有的执行参数放入数组中统一传递,其次还要选择带上p,我们输入的只有程序命令,带上p会自动在环境变量中寻找

至此,基本的框架我们已经搞定了。

  • shell运行原理

同时,在理解一下shell的运行原理:shell内部提取命令行做分析,然后调用exec. shell执行命令必须通过创建子进程,如果不创建子进程会把我们所有的shell全部替换,所以执行命令时一般磁盘上的程序必须创建子进程

  • 内建命令

我们在运行自己写的shell的时候,发现输入cd …输入cd path等命令时发现路径并没有改变!

image-20221130111814277

没有发生改变是因为自己写的shell执行很多命令都要fork()创建子进程,让子进程执行的cd,子进程有自己的工作目录,所以更改的子进程的目录,子进程执行完毕,继续用的是父进程,既shell,并没有影响父进程,所以并没有改变。

对于cd,我们可以采用内建命令:不需要创建子进程执行,让shell自己执行命令,称为内建命令。本质就是执行系统接口,我们可以调用一个系统接口chdir,可解决上述问题:

image-20221130142857416

image-20221130142956990

简易shell——代码实现

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#define NUM 1024
#define OPT_NUM 64
char lineCommand[NUM];
char *myargv[OPT_NUM];
int lastCode = 0;
int lastSig = 0;
int main()
{
    while(1)
    {
        //输出提示符
        printf("用户名@主机名 当前路径#");
        fflush(stdout);
        //获取输入
        char*s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
        assert(s != NULL);
        (void) s;
        lineCommand[strlen(lineCommand)-1] = 0;
        // printf("test:%s\n",lineCommand);
        //ls -a -l -i  字符串切割
        myargv[0] = strtok(lineCommand," ");
        int i = 1;
        if(myargv[0]!= NULL&& strcmp(myargv[0],"ls") == 0)
        {
            myargv[i++] =(char*)"--color=auto";
        }
        //如果没有子串,strtok会返回NULL                                                                   
        while(myargv[i++] = strtok(NULL," "));
        //如果是cd命令, 不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口
        //像这种不需要我们的子进程来执行,而是让shell自己执行的命令 --内建 内置命令
        if(myargv[0]!=NULL&& strcmp(myargv[0],"cd")==0)
        {
            if(myargv[1] != NULL) chdir(myargv[1]);
            continue;
        }
        if(myargv[0]!=NULL&& myargv[1]!=NULL && strcmp(myargv[0],"echo")== 0)
        {
            if(strcmp(myargv[1],"$?") == 0)                                                              
            {
                printf("%d %d\n",lastCode,lastSig);
            }
            else 
            {
                printf("%s\n",myargv[1]);
            }
              continue;
        }
        //利用条件编译测试代码是否成功
#ifdef DEBUG 
        for(int i = 0;myargv[i];i++)
        {
            printf("myargv[%d]:%s\n",i,myargv[i]);
        }
#endif
        //执行命令
        pid_t id = fork();
        assert(id!=-1);
        if(id == 0)
        {
            execvp(myargv[0],myargv);
            exit(1);
        }
        int status = 0;
        pid_t ret = waitpid(id,&status,0);
        assert(ret > 0);
        (void)ret;
        lastCode = ((status>>8)&0xFF);
        lastSig = (status & 0X7F);
    }
    return 0;
}

image-20221130152756486

image-20221130153006990

相关文章:

  • 融合多策略的萤火虫算法求解多目标优化问题(Matlab代码实现)
  • MacBook Pro 耗电严重的终极解决办法2022年
  • uni-fab彩色图标按钮
  • [附源码]Python计算机毕业设计Django的在线作业批改系统
  • TypeScript入坑
  • eMagin:当月产百万片时,4K MicroOLED成本将不是问题
  • [附源码]Python计算机毕业设计SSM乐多多宠物店网站(程序+LW)
  • JUC系列(五) 读写锁与阻塞队列
  • 2022最新iOS最新打包发布流程
  • 【Android进阶之旅】内存泄漏的危害有哪些?(案例分析)
  • 力扣(LeetCode)895. 最大频率栈(C++)
  • Effective C++条款18:让接口容易被正确使用,不容易被误用
  • ERP系统:帮助企业实现一体化管理
  • Python学习笔记第四十四天(NumPy 统计函数)
  • java计算机毕业设计花卉网站源码+mysql数据库+系统+lw文档+部署
  • Mysql高频面试题(一)
  • 如何确保海外服务器的高可用性?
  • 入门力扣自学笔记208 C++ (题目编号:895)
  • 水土保持监测,无人机倾斜摄影该如何做?
  • [附源码]Python计算机毕业设计Django电影院网上售票系统
  • 使用模板
  • jupyter notebook | 远程访问服务器及更换主题
  • 使用python切分mp4视频并保存每帧图像
  • centos7安装和编译opencv4.5.0
  • AutoML | AutoSklearn的基本分类、回归、多输出回归和多标签分类数据集的使用示例
  • 基于Python爬取Bing图片
  • 【26】pytorch中的grad求导说明以及利用backward获取梯度信息
  • 解决Kaggle新用户注册无法弹出验证提示的问题
  • 基于深度学习的二维码检测和识别(含完整代码和数据)
  • 【27】grad-cam的简单逻辑实现以及效果展示