linux进程篇总结——实战——自定义shell

news2024/11/28 2:52:10

        前言:经过过去两章十二篇文章的学习,我们已经知道了进程的基本概念以及进程的控制方法。 本篇内容就是使用过去学习的内容自己写一个功能简单的shell外壳程序, 也就是我们使用的bash命令行。 本篇内容是过去进程知识的集大成者。 我们在这个实战程序中, 将过去学过的进程控制方法——创建、等待、退出、终止,各种概念——PID、优先级、子进程、环境变量、命令行参数等等都会回忆起来, 复习起来。

        ps:本节内容很综合, 难度很大。需要学完进程的概念以及进程控制的方法。建议学习前先去复习一遍进程概念相关知识点。

目录

shell是什么        

实现过程

交互板块

命令行的外表

解决输入问题:

解析字符串

普通命令执行 

内建命令 

cd命令

ls颜色问题 

export 

echo


shell是什么        

        shell是外壳程序, 也就是说bash, shell本质上也是一个进程。 而在执行命令的时候, 对于普通命令本质上就是自己创建子进程执行的。而对于内建命令, bash命令其实是直接在自己上面调用的一个函数。 我们看到的bash命令行, 其实就是一个输出的字符串。 这个字符串是由用户名 + 主机名 + 当前路径组成的。 

        我们自己制作的shell主要分为几个板块——用户交互获取命令行、分解命令行参数、内建命令执行、普通命令执行

实现过程

交互板块

命令行的外表

用户名, 主机名,当前路径都保存在环境变量中。 

        那么, 我们就可以封装函数, 获取三个环境变量——一个是用户名、一个是主机名、一个是当前路径

主函数部分我们这里只写一下输出, 先将命令行的外表打印出来:

上图的三个黄框框是博主定义的宏, LEFT是打印"[", RIGHT是打印"]"。

然后对于普通用户最后一个字符一般都是$符号, 那么我们就定义一个LABLE的宏, 让这个宏替换$。如下图:

此时完整的代码如下:

此时运行结果就能打印一个属于我们自己的命令行:

解决输入问题:

但是不能输入, 接下来我们就解决输入问题。我们可以定义一个字符串,这个字符串的长度是1024。

在主函数这里添加一个scanf: 

要注意此时黄框框这里没有\n, 不然输入参数会多打印一个换行。 此时的运行结果如下, 可以输入了:

        但是此时只能输入, 这些输入的字符不能全部保存到commendline数组中。 因为scanf遇到空格会终止读取。 所以就用到了另一个输入函数——fgets , 如下图:

        fgets中, 第一个参数是要拷贝到的起始地址, 第二个参数是要拷贝的字节数, 第三个是从哪个文件读取。 我们是从显示器读取, 也就是stdin。

        上图的s用来接收fgets的返回值, fgets的返回值是读取成功后的地址, 如果读取不成功就是返回NULL。

        下图是运行结果:

        上面我们打印之所以多了一个换行, 是因为我们在输入的时候回车符被读取进去了。 也就是相当于printf那里有一个我们自己加的换行, 然后commendline最后一个字符也是一个换行。 commendline里面的换行是我们不想要的, 请问我们怎么去掉呢?——既然回车符是最后一个字符, 那么我们就把最后一个字符变成\0。如下图:

        下面是打印结果:

        现在, 我们将我们上面写的命令行的外表, 命令行的获取这些与用户交互的操作独自封装成一个函数——Interact。 

以上, 我们就实现了与用户的交互,获取命令行。 大体就是这样, 但是后续可能随着我们其他板块的增加, 修改里面的部分代码。 但不会影响大思路。

解析字符串

在正式解析字符串之前我们先把多次询问的问题解决。 因为我们的shell命令行是一直存在的, 不应该是使用一次后就退出。 这里我们要给代码套上一层循环。 ——即在我们要实现的逻辑:交互、解析、执行的外面套上一层死循环。这样就能让逻辑循环起来了。

        运行情况就是如下,程序正常情况下已经不会退出了。(ctrl + C可以退出) 

 

  接下来正式对命令行进行解析:

下面是解析的原理:

strtok函数如下:

 这里我们先定义一个分隔符的宏:

 

然后创建一个数组, 用来存储切割好的字符串。 

然后我们就实现截取字串, 将字串放到argv[i]中, 放进去后就i++, 等到截取不了了就返回一个空串。 但是strtok第一次截取的时候可以传参commendline, 如果之后还是截取这个字符串, 那么就传NULL,我们把解析字符串也单独封装成一个函数, 返回值是一个argc, 也就是截取出来的字符串的个数。 如下图:

写好之后, 我们就在主函数上放上测试代码:

如下就是分解后的效果:

普通命令执行 

        然后就是执行命令,当id == 0的时候执行。 

        这个时候, 如果execvpe加载成功, 就执行加载的程序如果加载失败, 就直接退出。并且退出码EXIT_CODE, 这个是我们自己定义的宏。

我们这里先定义一个lastcode获取状态信息:

        下面是执行普通命令的代码, environ是获取环境变量, 然后创建子进程, 如果id小于0的时候, 说明子进程创建失败, 那么直接返回。 如果id == 0, 说明是子进程,就加载程序。 我们的argv是数组, 所以带v, 但是没有绝对路径, 只有文件名, 所以要有默认搜索路径, 也就是加p。 另外还要有环境变量, 加上e。         

        如果是id > 0就说明是父进程, 父进程要等待子进程, 也就是下图的代码等待子进程。

然后, 我们运行我们的程序就可以执行一般的命令了。

内建命令 

cd命令

       但是, 这里有一个问题, 就是我们使用cd的时候, 我们会发现, 我们的工作目录不发生变化。这个是因为cd是一个内建命令!!!cd不是由bash的子进程加载得来的。就如同下图:

为什么会这样呢? 因为我们使用的fork创建的子进程。 子进程数据的修改不会改变父进程。 所以我们使用cd命令的时候, 虽然加载了cd命令, 但是子进程使用cd命令, 子进程工作路径修改, 不会影响父进程。 

        那么正常使用cd命令, 就不能创建子进程, 我们可以使用chdir。 现在是内建命令的处理:

        对于这些内建命令, 我们的解决方式是对于这些内建命令一个一个地做特殊处理。 首先, 为了方便维护, 我们同样将内建命令的执行封装成一个函数:

函数要带参数argc, 我们的代码都是在这个函数中完成。

内建函数创建后, 我们的大体逻辑就搭建好了, 现在来看一下主函数的逻辑——先交互, 再解析, 再执行:


回到cd上来,首先chdir可以修改路径。 chdir可以修改当前的工作路径。但是我们也要获取当前路径用来修改PWD环境变量。

这里我们可以使用getcwd, 先创建一个pwd字符数组, 用来保存当前工作路径:

然后将我们原先定义的pwd修改成下图:、

既然获取当前路径的代码变了, 我们上面写的代码中, 有些地方也要改, 首先是交互函数的修改, 下图的红框框是getpwd的使用, 黄框框是工作路径的获取:

然后是内建函数的修L

此时, 我们的cd就能跑了:

ls颜色问题 

处理颜色问题, 需要在最后加一个--color选项。 如果命令是ls, 那么就要处理一下, 也就是再最后加一个--color选项。 最好的是在命令行解析的函数里进行处理。 但是在里面处理会有argc的返回值问题。 所以为了方便, 博主这里放在了内建命令执行的函数里, 因为内建命令执行函数在普通命令执行函数之前, 并且博主的内建命令也有argc, 方便控制。 

当我们再运行时, 就能看到ls的颜色了:

写到这里的时候, 博主发现了一个问题, 就是我们可以给内建命令一个返回值, 只要返回真, 说明执行了内建命令, 假就没有执行。 这样就能防止又执行了内建, 又执行了普通。

export 

现在看一下新建环境变量export:

如果我们不做特殊处理, export创建环境变量, 是创建不出来的。因为我们直接使用export, 那就是创建子进程, 然后加载到子进程帮我们执行,然而子进程不会影响父进程。 所以就没有用处。如下图就是创建不出的例子:

        所以, 这里就需要将export也当作内建命令特殊处理——使用putenv在当前进程导入环境变量。 但是由于putenv导入环境变量只是修改环境变量的指针指向传给的参数指向的空间。也就是相当于一个浅拷贝。 如果我们直接给putenv传argv[1], 那么环境变量的指针指向putenv指向字符串, 当这个字符串被覆盖时环境变量就变了!!所以我们要先malloc一块新空间。 再将数据拷贝到这个空间。 让环境变量指向这块创建的malloc空间。

         当前进程导入环境变量。 那么就能使用我们自己的shell导入环境变量了。

echo

        对于echo也要做一下特殊处理。 因为一般情况下echo会打印正常, 但是对于环境变量来说, 它就会直接打印环境变量

        处理方式就是做一个特殊判断, 如果argv[1]的第一个字符时$那么就按照环境变量打印:

        如下图红框框处是做一下特殊判断, 防止发生段错误。 

        这样就能把环境变量打出来:

        但是还不行, 因为echo可能打印$, 也就是打印最后一次退出码。 

        那么就要再进行一次特殊处理:

lastcode里面保存了退出码, 当执行了一次echo $?后要把lastcode置为0

当我们当进行登录的时候, 我们的系统就是要启动一个shell进程。 我们shell本身的环境变量表是从哪里来的??——是在当前用户的家目录下, 有一个叫做bash_profile 或者 bashrc的文件。 这里面就有各种各样的文件。

        当用户登录的时候, shell会读取用户目录下的.bash文件, 里面保存了导入环境变量的方式!!!

        如果我们想要自己导入这种默认的环境变量, 那么我们就要和标准的shell一样, 创建一个环境变量表。 然后自己创建一个环境变量的配置文件。将这些环境变量读入环境变量表当中!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1985212.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧能源管理:助力公共机构节能增效

一、背景: 在全球倡导绿色发展、节能减排的时代浪潮下,公共机构作为社会服务的重要提供者,能源消耗量大,特别是在照明方面能源消耗问题尤为突出。从政府办公楼的日常照明,到学校教室的学习照明,再到医院走…

计算机组成原理 - 存储系统

存储系统 考纲内容 存储器的分类层次化存储器的基本结构半导体随机存储器(RAM) SRAM、DRAM、Flash存储器主存储器 DRAM芯片和内存条、多模块存储器、主存储器和CPU之间的连接外部存储器 磁盘存储器、固态硬盘(SSD)高速缓冲存储器(Cache) Cache的基本原理:Cache和主…

解读智慧车间生产线的智慧大脑:ARMxy 工业计算机边缘控制器

在现代工业制造中,智慧车间生产线的建设已成为提高生产效率、降低成本、提升产品质量的关键。而 ARMxy 工业计算机边缘控制器作为智慧车间生产线的智慧大脑,正发挥着越来越重要的作用。 ARMxy 工业计算机边缘控制器是一种基于 ARM 架构的嵌入式工业计算机…

JavaWeb基础1:HTML/CSS/JS/HTTP

JavaWeb基础1:HTML/CSS/JS/HTTP (qq.com)

C-sharp-console-gui-framework:C#控制台应用程序的GUI框架

推荐一个.Net开源项目,方便我们基于控制台创建图形用户界面(GUI)应用程序。 01 项目简介 ConsoleGUI是一个简单的布局驱动.NET框架,用于创建基于控制台的GUI应用程序。 核心功能: **布局驱动:**与WPF或H…

WCN7851 WIFI7适配RK3588实战

一、平台信息 平台:触觉智能IDO-EVB3588-V1 WIFI模组:欧飞信O7851PM Kernel版本:GNU/Linux 5.10.110 aarch64 系统版本:Ubuntu 20.04.6 LTS 搭载RK3588高性能SOC,集成了四核Cortex-A76和四核Cortex-A55 CPU,主频高达2.4G O7851PM与开发板连接实物图如下,模块通过M.2转…

ctfhub文件上传

⽆验证 上传⼀句话⽊⻢&#xff0c;发现上传成功 1.php ⼀句话⽊⻢内容&#xff1a; <?php eval($_POST[cmd]);?> 上传⼀句话⽊⻢&#xff0c;发现上传成功 http://challenge-8b27d18368ecc25c.sandbox.ctfhub.com:10800/upload/1.ph p 前端验证 开启题⽬ 上传⼀个…

学习日志8.5--ARP攻击与防范

目录 ARP欺骗攻击 ARP泛洪防范&#xff08;动态ARP检测&#xff09; ARP欺骗攻击 ARP中间人攻击&#xff0c;中间人可以通过交换机查询交换表获取主机和网关的IP地址信息中间者通过ARP的查询可以知道PC2的IP地址和MAC地址&#xff0c;知道R2的IP地址和MAC地址&#xff0c;攻…

CVE-2023-1313

开启靶场 url访问/install来运行安装 http://eci-2ze0wqx38em0qticuhug.cloudeci1.ichunqiu.com/install/ 得知其用户和密码为admin 登录 查找文件上传位置 上传一句话木马文件 <?php echo phpinfo();eval($_POST[flw]);?> 下载查看上传木马路径 复制路径 /storag…

59 函数参数——默认值参数

在定义函数时&#xff0c;Python 支持默认值参数&#xff0c;在定义函数时可以为形参设置默认值。 在调用带有默认值参数的函数时&#xff0c;可以不用为设置了默认值的形参进行传递&#xff0c;此时函数将会直接使用函数定义时设置的默认值&#xff0c;当然也可以通过显式赋值…

第四届机械制造与智能控制国际学术会议(ICMMIC 2024,9月27-29)

2024年第四届机械制造与智能控制国际学术会议&#xff08;ICMMIC 2024&#xff09;将于2024年9月27-29日在中国沈阳沈阳理工大学举行。 本会议将围绕“机械制造、智能控制”的最新研究领域&#xff0c;促进机械工程、兵器科学与技术、控制科学与工程等相关学科的发展与交叉融合…

AUTOSAR之ECUM

1、EcuM简介 EcuM&#xff08;ECU State Management&#xff09;ECU状态管理模块属于AUTOSAR系统服务中模式管理部分&#xff0c;主要功能是管理ECU的上下电&#xff0c;初始化和反初始化OS&#xff0c;SchM&#xff0c;BswM以及其他一些驱动模块。 AUTOSAR 4.4版本前Ec…

WPF学习(5)- Border控件(边框布局)+GridSplitter分割窗口

严格来说&#xff0c;Border并不是一个布局控件&#xff0c;因为它并不是Panel的子类&#xff0c;而是Decorator装饰器的子类&#xff0c;而Decorator继承于FrameworkElement。我们要先看看它的父类Decorator。 public class Decorator : FrameworkElement, IAddChild {public…

【区块链+医疗健康】医保监管飞检魔方可信链 | FISCO BCOS应用案例

《“十四五”全民医疗保障规划》提出加快健全基金监管体制机制&#xff0c;要求飞行检查全覆盖。近年来&#xff0c;国家医保局 飞行检查专项行动&#xff0c;累计发现问题 70 多万家次&#xff0c;累计追回医保基金 340 多亿元。而飞行检查面临检查时间短、 工作任务重、数据多…

Linux 使用kickstart创建脚本实现新建虚拟机自动安装

Linux版本&#xff1a;红帽7.9 确保网络配置可用&#xff0c;本地仓库可用&#xff0c;同时已经挂载/dev/cdrom,可用yum list查看 一、环境配置&#xff1a; 1、首先保证是有图形界面 利用hostnamectl 查看 如果没有安装图形界面可以使用yum group install "Server wi…

源码编译安装LAMP(HTTP服务,MYSQL ,PHP)

一、安装Apache 可在生产环境使 下载在 下面两个插件是httpd2.4以后的版本所需要 tar xf apr-1.6.2.tar.gz tar xf apr-util-1.6.0.tar.gz 虽然xf通常足够&#xff0c;但使用与压缩算法对应的选项可以提供更好的控制。 tar xjf httpd-2.4.29.tar.bz2 mv apr-1.6.2 httpd-2.4.…

How to run OpenAI Gym .render() over a server

题意&#xff1a;怎样在服务器上运行 OpenAI Gym 的 .render() 方法 问题背景&#xff1a; I am running a python 2.7 script on a p2.xlarge AWS server through Jupyter (Ubuntu 14.04). I would like to be able to render my simulations. 通过 Jupyter&#xff08;在 U…

鸿蒙Navigator跳转不生效的问题

新增配置文件&#xff1a; 注意&#xff1a;该文件要在moudle中配置引用&#xff0c;非则跳转无法生效&#xff1a;

[Meachines] [Easy] Sunday Finger网络用户枚举+Wget文件覆盖权限提升

信息收集 IP AddressOpening Ports10.10.10.76TCP:79, 111, 515, 6787, 22022 $ nmap -p- 10.10.10.76 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 79/tcp open finger? | fingerprint-strings: | GenericLines: | No one logged on | GetReque…

黑马Java零基础视频教程精华部分_14_正则表达式

系列文章目录 文章目录 系列文章目录一、先爽一下正则表达式不使用正则的情况下使用正则的情况下 二、正则表达式的作用三、正则表达式具体表达1、规则2、字符类示例3、预定义字符示例首先学习转义字符 示例练习 四、基本练习1、快捷方法&#xff1a;2、验证手机号3、验证座机电…