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…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...

工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...