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

【Linux】实现简易的Shell命令行解释器

大家好我是沐曦希💕

文章目录

  • 一、前言
  • 二、准备工作
    • 1.输出提示符
    • 2.输入和获取命令
    • 3.shell运行原理
    • 4.内建命令
    • 5.替换
  • 三、整体代码

一、前言

前面学到了进程创建,进程终止,进程等待,进程替换,那么通过这些来制作一个简易的Shell命令行解释器。

首先这是与Shell的互动:
在这里插入图片描述
用下图的时间轴来表示事件的发生次序。其中时间从左向右。shell由标识为sh的方块代表,它随着时间的流逝从左向右移动。shell从用户读入字符串"ls"。shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。
在这里插入图片描述
然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序 并等待这个进程结束。所以要写一个shell,需要循环以下过程:

1. 获取命令行
2. 解析命令行
3. 建立一个子进程(fork)
4. 替换子进程(execvp)
5. 父进程等待子进程退出(wait)

二、准备工作

1.输出提示符

在这里插入图片描述
这里的提示字符为用户名@主机名 当前路径# 直接打印出来作为提示所用

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

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

2.输入和获取命令

  • 输入

我们需要输入一连串命令,其中可能出现空格,所以不能使用gets函数,需要用到fgets函数,同时,可以定义一个lineCommand[NUM]数组

#define NUM 1024
char lineCommand[NUM];
char* s = fgets(lineCommand,sizeof(lineCommand) - 1, stdin);
assert(s != NULL);

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

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

可以通过打印看看效果和测试是否有BUG

printf("test:%s\n",lineCommand);

在这里插入图片描述

  • 获取

输入之后,我们自然需要去进行获取,我们需要分割命令行,这个地方用strtok。把字符串切割成若干个子串:
strtok:第一次直接传递参数,第二次则必须传NULL。且在最终strtok会返回NULL。

在这里插入图片描述

在这里插入图片描述

3.shell运行原理

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

4.内建命令

我们在运行自己写的shell的时候,发现输入cd …输入cd path等命令时发现路径并没有改变!
在这里插入图片描述
没有发生改变是因为自己写的shell执行很多命令都要fork()创建子进程,让子进程执行的cd,子进程有自己的工作目录,所以更改的子进程的目录,子进程执行完毕,继续用的是父进程,既shell,并没有影响父进程,所以并没有改变。

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

5.替换

采用execvp进行替换进程

pid_t id = fork();
assert(id != -1);
if(id == 0)
{execvp(myargv[0],myargv);exit(1);
}

三、整体代码

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#include<assert.h>#include<string.h>#define NUM 1024#define OPT_NUM 64char lineCommand[NUM];char *myargv[OPT_NUM];//指针数组int lastcode = 0;int lastsig = 0;int main(){while(1){// 1.输出提示符printf("lj@VM-8-2-centos 当前路径#");fflush(stdout);// 2.获取用户输入的命令,输入的时候,用户最后还输入了\nchar* s = fgets(lineCommand,sizeof(lineCommand) - 1, stdin);assert(s != NULL);(void)s; //避免Linux认为s变量未使用,导致警告// 清除最后一个\n;例如:abcd\nlineCommand[strlen(lineCommand) - 1] = 0;//printf("test:%s\n",lineCommand);// "ls -a -l -i" -->字符串分割-->"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,即myargv[end] = NULLwhile(myargv[i++] = strtok(NULL," "));//如果是cd命令,不需要创建子进程,让shell自己执行对应的命令,本质就是执行系统接口//像这种不需要让我们的子进程来执行,而是让shell自己执行的命令—内建命令//其中echo是一个自建命令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[i]);}continue;}//利用条件编译测试是否成功#ifdef DEBUGfor(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;}

在这里插入图片描述

相关文章:

【Linux】实现简易的Shell命令行解释器

大家好我是沐曦希&#x1f495; 文章目录一、前言二、准备工作1.输出提示符2.输入和获取命令3.shell运行原理4.内建命令5.替换三、整体代码一、前言 前面学到了进程创建&#xff0c;进程终止&#xff0c;进程等待&#xff0c;进程替换&#xff0c;那么通过这些来制作一个简易的…...

再获认可!腾讯安全NDR获Forrester权威推荐

近日&#xff0c;国际权威研究机构Forrester发布最新研究报告《The Network Analysis And Visibility Landscape, Q1 2023》&#xff08;以下简称“NAV报告”&#xff09;&#xff0c;从网络分析和可视化&#xff08;NAV&#xff09;厂商规模、产品功能、市场占有率及重点案例等…...

代码审计之旅之百家CMS

前言 之前审计的CMS大多是利用工具&#xff0c;即Seay昆仑镜联动扫描出漏洞点&#xff0c;而后进行审计。感觉自己的能力仍与零无异&#xff0c;因此本次审计CMS绝大多数使用手动探测&#xff0c;即通过搜索危险函数的方式进行漏洞寻找&#xff0c;以此来提升审计能力&#xf…...

ONLYOFFICE中利用chatGPT帮助我们策划一场生日派对

近日&#xff0c;人工智能chatGPT聊天机器人爆火&#xff0c;在去年年底发布后&#xff0c;仅仅两个月就吸引了全球近一亿的用户&#xff0c;成为史上最快的应用消费程序&#xff0c;chatGPT拥有强大的学习和交互能力 可以被学生&#xff0c;教师&#xff0c;上班族各种职业运…...

Java面试题-线程(一)

在典型的 Java 面试中&#xff0c; 面试官会从线程的基本概念问起&#xff0c; 如&#xff1a;为什么你需要使用线程&#xff0c;如何创建线程&#xff0c;用什么方式创建线程比较好&#xff08;比如&#xff1a;继承 thread 类还是调用 Runnable 接口&#xff09;&#xff0c;…...

一篇普通的bug日志——bug的尽头是next吗?

文章目录[bug 1] TypeError: method object is not subscriptable[bug 2] TypeError: unsupported format string passed to numpy.ndarray.__format__[bug 3] ValueError:Hint: Expected dtype() paddle::experimental::CppTypeToDataType<T>::Type()[bug 4] CondaSSLE…...

Vue 3 第八章:Watch侦听器

文章目录Watch侦听器1. 基础概念1.1. Watch的基本用法例子1&#xff1a;监听单个ref的值&#xff0c;直接监听例子2&#xff1a;监听多个ref的值&#xff0c;采用数组形式例子3&#xff1a;深度监听例子4&#xff1a;监听reactive响应式对象单一属性&#xff0c;采用回调函数的…...

GlassFish的安装与使用

一、产品下载与安装glassfish下载地址&#xff1a;https://download.oracle.com/glassfish/5.0.1/release/index.html下载后解压即完成安装&#xff0c;主要目录说明&#xff1a;bin目录&#xff1a;为asadmin命令所在目录。glassfish为主目录&#xff1a;glassfish\bin目录为命…...

【java】Java 重写(Override)与重载(Overload)

文章目录重写(Override)方法的重写规则Super 关键字的使用重载(Overload)重载规则实例重写与重载之间的区别总结重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变&#xff0c;核心重写&#xff01; 重写的好处在于…...

OpenCV-PyQT项目实战(12)项目案例08:多线程视频播放

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …...

面向对象设计模式:结构型模式之装饰器模式

文章目录一、引入二、装饰器模式2.1 Intent 意图2.2 Applicability 适用性2.3 类图2.4 优缺点2.5 应用实例&#xff1a;Java IO 类2.6 应用实例&#xff1a;咖啡馆订购系统一、引入 咖啡馆订购系统 Initial 初始 4 种咖啡 House blend (混合咖啡)Dark Roast (深度烘培)Decaf (…...

Unity iOS 无服务器做一个排行榜 GameCenter

排行榜需求解决方案一(嗯目前只有一)UnityEngine.SocialPlatformsiOS GameCenterAppStoreConnect配置Unity 调用(如果使用GameCenter系统的面板&#xff0c;看到这里就可以了&#xff09;坑(需要获取数据做自定义面板的看这里)iOS代码Unity 代码吐槽需求 需求&#xff1a;接入…...

现在招个会自动化测试的人是真难呀~你会个锤子的自动化测试

现在招个会自动化测试的人是真难呀~ 前一段时间公司计划要招2个自动化测试到岗&#xff0c;同事面试了十几个来应聘的人&#xff0c;发现一个很奇怪的现象&#xff0c;在面试的时候&#xff0c;如果问的是框架API、脚本编写这些问题&#xff0c;基本上所有人都能对答如流&…...

OracleDatabase——数据库表空间dmp导出与导入

由于公司的程序一直部署在客户现场内网&#xff0c;内网调试难度高&#xff0c;一般是有备份还原数据库的需求&#xff0c;这里简记备份&#xff08;导出&#xff09;数据库dmp文件与恢复&#xff08;导入&#xff09;的步骤。 一、导出dmp文件 exp与expdp命令异同 相同点&a…...

20张图带你彻底了解ReentrantLock加锁解锁的原理

哈喽大家好&#xff0c;我是阿Q。 最近是上班忙项目&#xff0c;下班带娃&#xff0c;忙的不可开交&#xff0c;连摸鱼的时间都没有了。今天趁假期用图解的方式从源码角度给大家说一下ReentrantLock加锁解锁的全过程。系好安全带&#xff0c;发车了。 简单使用 在聊它的源码…...

Dockerfile构建Springboot镜像

Dockerfile构建Springboot镜像 文章目录 Dockerfile构建Springboot镜像 简介实例演示 前期准备 Docker环境Springboot项目Dockerfile文件 Windows 要求构建镜像启动测试 Linux 要求构建镜像启动测试 简介 容器技术大流行的时代&#xff0c;也是docker大流行的时代。 此文…...

从深分页查询到覆盖索引

最近看到一道面试题&#xff0c;如何优化深分页查询 最简单的例子是 select * from web_bill_main limit 30000,10;分页达到30000行&#xff0c;需要把前面29999行都过滤掉&#xff0c;才能找到这10条数据 所以整体时间花了80ms(工具显示时间) 我当时的第一反应是&#xff0…...

Go语言学习的第三天--下部分(Gin框架的基础了解)

每天都会分享Go的知识&#xff0c;喜欢的朋友关注一下。每天的学习分成两部分基础&#xff08;必要的&#xff0c;基础不牢地动山摇&#xff09;&#xff0c;另一部分是Go的一些框架知识&#xff08;会不定时发布&#xff0c;因为小Wei也是一名搬砖人&#xff09;。但是可以保证…...

JDK的动态代理(powernode 文档)(内含源代码)

JDK的动态代理&#xff08;powernode 文档&#xff09;&#xff08;内含源代码&#xff09; 源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87546086 一、动态代理 目录JDK的动态代理&#xff08;powernode 文档&#xff09;&#xff0…...

第1章 多线程基础

第1章 多线程基础 1.1.2 线程与进程的关系 进程可以看成是线程的容器&#xff0c;而线程又可以看成是进程中的执行路径。 1.2 多线程启动 线程有两种启动方式&#xff1a;实现Runnable接口&#xff1b;继承Thread类并重写run()方法。 执行进程中的任务时才会产生线程&a…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...