Linux 简易shell编写
shell
shell是壳,外壳的意思,一般我们使用linux系统有用图形化界面的也有使用命令行界面的,这两个都是一种shell,以命令行为例:

如图
这个就是我这里的命令行格式,在$符后面写的就是执行的指令,ls指令在linux中也是一个可执行程序,这个程序作用就是显示出当前路径下的文件。可是能执行命令程序就代表我们找到这个文件并对其进程了执行的操作,而我们只是在$符后面写下了ls而已-l是一个选项是传递给ls这个程序的一个参数。能完成找到ls程序并执行它并将参数传递给这个程序的工作就是shell做的事。所以shell也是为了完成某一目的而被编写出来的一个程序,这个程序会在我们打开软件的时候自动执行。我这里用的是XSHELL5也是这个软件的功能之一。
在shell环境下编写shell,我们为什么能在shell环境下编写使用shell呢,这就是shell进程设计的工作模式,当我们使用命令行执行一个程序的时候shell程序会被挂起执行启动的程序,直到我们启动的程序结束shell程序才会接管执行,这个就是父子进程的关系,shell进程作为父进程,命令行输入的程序作为子进程,当执行子进程时父进程对子进程进行等待,子进程结束后父进程在等待后继续执行,这就是shell的工作模式。
shell命令行
![]()
我们能看到当进入程序的时候一开始就会看到这样一个命令行提示字符串,里面有我现在用户名,有主机名,有当前路径名字。
这就是shell的第一个模块,进入shell我们需要先有一个提示的字符串

这个是打印命令行提示的代码,先定义一个字符数组用于存放完整的提示,定义了三个字符串指针用于接收对应的数据



这里对应着三个所调用的函数分别是获取用户名,获取主机名,获取路径。三个函数用的是同一个库函数getenv作用是根据传递的参数在环境变量中找寻对应的值。返回字符串首位的地址,然后将这个字符串返回。
由于这里通过环境变量返回的路径是绝对路径所以这里我做了一点小修改

只截取了最后的一个路径,不然整个命令行提示会随着层数加深越来越长。

然后我们只要按照一定的格式将其写入到一开始定义的字符数组中然后打印到屏幕上因为我们后续是直接在命令行提示后面直接写入指令的所以这里不需要要换行,但是系统缓冲区的刷新是按照行刷新的所以这里需要手动刷新标准输出的缓冲区。
获取指令
指令我们都是从命令行中获取,而命令行中其实就是打印了标准输入中的数据,所以实际上是从标准输入中获取的。
因为每次输入都是新的指令,旧的指令就放弃掉,有很多外壳程序会有存储上几条输入的指令所以我们是可以malloc一个缓冲区来存放需要存储的指令的,但是我们这里就简单实现就直接对之前的指令不做处理默认丢弃
![]()
我这里在main函数中定义了一个字符数组存放指令这个数组过了生命周期就自动释放每次获取的时候就从新创建,然后将这个数组作为输出型参数传递给获取指令的函数。

这个数组的大小是需要传递的,因为数组传参是传的指针,数组的大小只能在定义的作用域内计算。然后使用fgets函数从标准输入中获取指令到缓冲区中。
标准输入中是不会包含字符串结束符的,"\0"作为字符串的结束标志是C语言中规定的,这里需要自己添加进去,这里返回获取到的字符串的长度。这里不用scanf的原因是scanf遇到空格会当作输入结束就无法获取一整行的指令。

问我这里判断输入用<=0表示程序出错了直接停止程序,因为无论在命令行中输入什么都不可能出现<=0的情况就算只输入了空格回车那也有一个空格符或者回车。
指令分割
指令接收是一整行的,但是里面包含了程序名或路径加程序名还有一些选项,就需要将选项和程序分割开来。
这里将参数分割开来后需要存储,这里定义一个全局的字符指针数组存放。![]()

这里使用strtok函数分割,这个函数有一些些奇怪,第一次分割需要把其实地址和分割的符号传进去这里SEP是一个宏
是一个空格,这个分隔符是一个字符串不是字符。然后继续分割就不需要地址了,给他一个NULL会自动在之前的位置继续分割,他会返回分割后的首字符指针,第一个分割的还在原来的缓冲区中,后续分割的会存放在静态区中,这是strtok的性质,所以分割后最好不要继续使用main函数中的缓冲区的用户指令了,我们会将分割后指令和选项的字符串首地址放在全局的字符指针数组中,后续就用这个数组就可以了。
指令执行
分割完指令我能就从全局的字符指针数组中获取单个的指令和选项了,那就可以执行这个指令了,这个指令也是一个程序,我们也没必要将所有程序功能都集中在shell程序中,而且都有现成的还去实现这么的程序功能这样耦合度过高不好,效率也不行,所以我们需要在创建一个执行指令的进程。这里我们使用子进程加程序替换的方式来实现。

子进程的创建替换,父进程的等待都打包给了函数,就不需要主进程这么麻烦了,直接调用就可以了。进程创建替换详细在进程篇中,就说一下execvp这个函数,exec函数家族有好几个函数,主要是参数不同能适应各种场景,这里使用vp是可以直接匹配系统的环境变量就不需要我们自己自定义环境变量了传参了,v是数组的意思我们能以数组的形式传递选项的参数,我们定义的参数列表就是一个字符指针数组所以用这个函数最方便了,第一个参数传入我们需要执行的程序名或路径加程序名,然后将整个参数列表都传入给第二个参数就完成进程替换,若失败返回-1,设置错误码,我们子进程直接退出返回错误码给父进程,若是成功就变成了第一个参数的程序了就不用管了。
父进程就只需要等待子进程完成就可以了,这里我们只对进程替换失败做一些工作,获取错误码并打印。
内建指令
完成上述步骤最简单的外壳程序就已经完成了,能获得用户输入的信息并创建子进程执行对应的程序。只是还有一些小瑕疵,有一些指令例如cd指令要变更当前路径,但这里是创建子进程执行这个程序所以父进程的路径并不会更改,而是子进程的路径被更改了,子进程路径被修改是没有意义的,我的都是从shell程序作为基点来使用linux系统的,所以这条指令需要由父进程自己执行,类似这种的指令叫做内建指令,不能由子进程执行。

在调用子执行函数前先检查是否为内建命令若是就单独执行这个命令,不然子进程执行。

cd指令比较复杂因为不止要执行还需要对环境变量进行更改,还要对命令行提示进行修改所以单独写了一个函数执行,这里先拿到指令的第二个参数即数组下标为一的参数,若这个参数为NULL就说明用户只写了cd,这时我们调用一个函数获取环境变量中的home路径

这个正常的系统都是有的,没有的那些要不自己更改了,要不系统就有些错误了。不过我们还是将没有的也考虑了一下返回一个根目录。
然后使用系统调用函数更改当前路径,这里参数是用的绝对路径。
更改完路径需要对环境变量中的路径进行修改,先定义一个存放新路径的字符数组,使用getcwd这是个c库函数,获取当前的最新路径,然后以标准格式存放,这里是用了一个全局的cwd字符数组存放
![]()
这时系统env里面的标准格式,getcwd是只获得路径,前面的PWD=需要手动添加上去,然后使用putenv函数更新当前工作路径完成cd全部步骤。
相关文章:
Linux 简易shell编写
shell shell是壳,外壳的意思,一般我们使用linux系统有用图形化界面的也有使用命令行界面的,这两个都是一种shell,以命令行为例: 如图这个就是我这里的命令行格式,在$符后面写的就是执行的指令,…...
POLYGON Nature - Low Poly 3D Art by Synty 树木植物
一个低多边形资源包,包含可以添加到现有多边形风格游戏中的树木、植物、地形、岩石、道具和特效 FX 资源。 为 POLYGON 系列提供混合样式树这一新增功能。弥合 POLYGON 与更传统的层级资源之间的差距。还提供了一组经典的 POLYGON 风格的树木和植被以满足你的需求。 该包还附带…...
了解什么是瞪羚企业
瞪羚企业”是指以科技创新或商业模式创新为支撑,进入高成长期的中小企业。识别范围主要是符合国家和省战略性新兴产业发展方向的产业领域,涵盖新兴产业、新一代信息技术(包括大数据、物联网和云计算、高端软件、互联网)、生物健康…...
寻找两个正序数的中位数(C)
最近面试,发现要手撕算法加上机试,被完败,索性给自己立一个目标,一周训练2次。 第一题。 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 …...
YOLOv10涨点改进:IoU优化 | Unified-loU,用于高品质目标检测的统一loU ,2024年8月最新IoU
💡💡💡现有IoU问题点:IoU (Intersection over Union)作为模型训练的关键,极大地显示了当前预测框与Ground Truth框之间的差异。后续研究者不断在IoU中加入更多的考虑因素,如中心距离、纵横比等。然而,仅仅提炼几何差异是有上限的;而且新的对价指数与借据本身存在潜在…...
Spring Boot 实现动态配置导出,同时支持公式和动态下拉框渲染和性能优化案例示范
在业务系统中,数据导出是一个非常常见且重要的功能,本文将详细介绍如何在 Spring Boot 中实现这一功能,并结合 MySQL 数据库、MyBatis 作为数据访问层,EasyExcel 作为导出工具,展示如何在电商交易系统中搭建灵活、可扩…...
一网打尽 运维必封的50个高危端口清单,零基础入门到精通,收藏这一篇就够了
文件传输相关端口: • TCP 20、21:FTP 服务(文件传输协议)端口,FTP 传输数据时未加密,容易受到攻击,如匿名上传下载、爆破、嗅探、远程执行等攻击,可能导致敏感文件泄露。 • TCP …...
方法 WebDriverWait
定义: WebDriverWait是Selenium WebDriver提供的一个工具类,它允许你设置等待条件,直到这个条件成立,才继续执行代码。这对于处理网页上的异步加载元素特别有用,比如等待某个元素变得可见、可点击等。 from se…...
LOESS(Locally Estimated Scatterplot Smoothing)
文章目录 LOESS 原理详解:LOESS 的优点:LOESS 的缺点:Python 实现代码:代码说明: LOESS(Locally Estimated Scatterplot Smoothing),即局部加权回归,是一种非参数回归方法…...
每天学习一个技术栈 ——【Django Channels】篇(1)
在当今快速发展的技术领域,掌握多种技术栈已经成为开发者提升竞争力的关键。随着实时应用需求的不断增加,如何高效地处理并发请求和实时通信变得尤为重要。在众多解决方案中,Django Channels作为Django框架的强大扩展,能够轻松实现…...
js设计模式-工厂模式 单例模式 观察者模式 发布订阅模式 原型模式 代理模式 迭代器模式
1 工厂模式 // 工厂模式: 调用函数返回对象function factory(name, age){return {name: name,age: age} }const person1 factory(Tom, 18); // 类似的库使用工厂函数的有: jQuery, React.createElement,axios.create,vue.createApp等 2 单例模式 // 单例模式:单…...
关于Java中的List<User>如何进行深拷贝
联调中发现了一个很初级,但有容易被忽略的拷贝问题: 错误方式:List<User> us new ArrayList<>(); // name "张三"List<User> us1 new ArrayList<>(us);for (User u : us) {...u.setName("douzi&q…...
2025 年 IT 前景:机遇与挑战并存,人工智能和云计算成重点
云计算de小白 投资人工智能:平衡潜力与实用性 到 2025 年,人工智能将成为 IT 支出的重要驱动力,尤其是在生成式人工智能领域。人工智能的前景在于它有可能彻底改变业务流程、增强决策能力并开辟新的收入来源。然而,现实情况更加微…...
Cortex-A7和Cortex-M7架构处理器取中断向量全流程分析
0 参考资料 Cortex M3权威指南(中文).pdf ARM Cortex-A(armV7)编程手册V4.0.pdf1 Cortex-A7和Cortex-M7处理器架构取中断向量全流程分析 1.1 什么是中断向量? 中断向量就是中断服务函数入口地址,例如我们发生了EXTI0中断,就需要执行EXT0中…...
MODELS 2024震撼续章:科技与可持续性的未来交响曲
MODELS 2024国际会议正如火如荼地进行着,每一天都充满了新的发现与启迪,每一场分享都是对技术前沿的一次深刻探索,更是对现实世界可持续性挑战的一次积极回应。现在让我们继续这场科技盛宴,看看小编为您精选几场的学术分享吧~ 会议…...
CICD 持续集成与持续交付
一 、CICD是什么 CI/CD 是指持续集成(Continuous Integration)和持续部署(Continuous Deployment)或持续交付(Continuous Delivery) 1.1 持续集成(Continuous Integration) 持续集…...
“数据面”(Data Plane)是指负责实际数据处理和转发的部分
在计算机网络和服务架构中,“数据面”(Data Plane)是指负责实际数据处理和转发的部分。数据面负责执行具体的网络通信任务,如接收、处理和转发数据包。与数据面对应的是“控制面”(Control Plane)ÿ…...
面试题:MySQL你用过WITH吗?领免费激活码
感谢Java面试教程的Java多线程文章,点击查看>原文 Java面试教程,发mmm116可获取IDEA-jihuoma 在MySQL中,WITH子句用于定义临时表或视图,也称为公共表表达式(CTE)。它允许你在一个查询中定义一个临时结果…...
consul 介绍与使用,以及spring boot 项目的集成
目录 前言一、Consul 介绍二、Consul 的使用三、Spring Boot 项目集成 Consul总结前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是…...
Linux常用命令shell常用知识 。。。。面试被虐之后,吐血整理。。。。
Linux三剑客&常用命令&shell常识 Linux三剑客grep - print lines matching a patternsed - stream editor for filtering and transforming textawkman awk Linux常用命令dd命令ssh命令tar命令curl命令top命令tr命令xargs命令sort命令du/df/free命令 shell 知识functio…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
