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…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
