【Linux课程学习】:《简易版shell实现和原理》 《哪些命令可以让子进程执行,哪些命令让shell执行(内键命令)?为什么?》
🎁个人主页:我们的五年
🔍系列专栏:Linux课程学习
🌷追光的人,终会万丈光芒
🎉欢迎大家点赞👍评论📝收藏⭐文章


目录
打印命令行提示符(PrintCommandLine):
1.USER和LOGNAME(用户名):
2.HOSTNAME和PWD:
获取命令行信息(GetCommadLine)
读取时,处理换行符:
解析命令行(ParseCommandLine)
执行命令(ExecuteCommand)
哪些命令可以让子进程执行,哪些命令不能让子进程执行?为什么?
通过getcwd获取实时的cwd,通过putenv导入环境变量:
myshell维护自己的环境变量:
1.我们让子进程执行cd ..命令的时候,为什么我们执行pwd命令的时候,还是和之前一样,路径没有变化?
本质就是,我们更改的是子进程的环境变量pwd,没有改变父进程的。当执行pwd时,这个进程的环境变量还是由父进程来的。而父进程的环境变量没有改变,所以pwd出来的结果也没有改变。
2.环境变量是由shell自己维护的。
3.在这个简易版shell中,我们没有维护这个环境变量,还是依靠系统的环境变量。当环境没有修改,用的还是系统的环境变量,更改时才写时拷贝。
4.echo命令也是内键命令,因为子进程不会继承父进程的本地环境变量。所以要打印本地变量,只有由shell来做。
打印命令行提示符(PrintCommandLine):
启动shell程序,就是创建-bash进程,本质就是一个进程。
首先看到命令行的提示符是这样的:
[kym@hcss-ecs-32c9 2024-11-26]$
包括:
1.用户名。2.主机名。3.当前的路径。4.命令行提示符。($)

1.USER和LOGNAME(用户名):
LOGNAME:
USER和LOGNAME都与当前用户有关,但LOGNAME是POSIX标准的一部分,更加标准化和一致,所以更推荐用LOHNAME确定当前的用户的登录身份。
USER:
USER的环境变量可能在某些系统中与LOGNAME有相同的值,但因为其行为不一致,在精确用户身份的时候应该慎用。
2.HOSTNAME和PWD:
通过环境变量获取这些信息。
三个函数获得用户信息(GetLOGNAME),主机信息(GetHOSTNAME),当前路径信息(GetPWD)。
通过string进行传递,如果要谁用c语言的字符串,就通过c_str()进行获得底层char。
头文件:
#include <stdio.h>
函数原型:
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);将这些输入到一个字符串中。
const size_t basesize=1024;//获取用户名信息string GetLOGNAME(){string log_name=getenv("LOGNAME");return log_name.empty()?"None":log_name;}//获取当前主机信息string GetHSOTNAME(){string host_name=getenv("HOSTNAME");return host_name.empty()?"None":host_name;}//获取当前路径信息string GetPWD(){ string pwd=getenv("PWD"); if(pwd.empty()) return "None"; string separator="/"; string sub_str=pwd.substr(pwd.find_last_of(separator)+1); return sub_str; }//生成command_line字符串 string MakeCommandLine() {//[kym@hcss-ecs-32c9 2024-11-26]$ char command_line[basesize]; snprintf(command_line,basesize,"[%s@%s %s]@",\GetLOGNAME().c_str(),\ GetHSOTNAME().c_str(),\GetPWD().c_str());return command_line;}// //1.打印命令行提示符void PrintCommandLine(){printf("%s",MakeCommandLine().c_str());fflush(stdout);}
获取命令行信息(GetCommadLine)
bool GetCommandLine(char command_buff[],size_t size)
{char* result=fgets(command_buff,size,stdin);if(result==NULL)return false;result[strlen(result)-1]=0;return true;
}
读取失败返回false,读取成功把换行符覆盖。
读取时,处理换行符:
如果我们以一行来读取字符串,那么最会就有换行符,换行符也会读取进来。所以打印的时候,我们没有加换行,也是来到了新的一行。
解决办法:
在返回前,把\n置为0。
result[strlen(result)-1]=0;
解析命令行(ParseCommandLine)
通过strtok函数进行分解字符串。

#include <string.h>
char *strtok(char *str, const char *delim);
bool ParseCommandLine(char command_buff[],int len)
{ (void)len; argc=0; //初始化 memset(argv,0,sizeof(argv)); const char* sep=" "; argv[argc++]=strtok(command_buff,sep); while((bool)(argv[argc++]=strtok(nullptr,sep))); argc--; return false;
}
sep表示分隔符,用来把字符串进行分解。但是在分解之前,我们需要把argc和argv进行初始化。每次执行新的命令。
strtok函数第一次调用的时候,str指向要分割的字符串。在后续的调用中传NULL。因为strtok函数内部有静态变量维护当前字符串的位置。
执行命令(ExecuteCommand)
通过子进程发生程序替换。当id==0,表示子进程。如果发生了程序替换,还执行了原来的exit,就表示发生错误。然后就是父进程子进程。
bool ExecuteCommand()
{ pid_t id=fork(); if(id<0) return false; if(id==0) { execvp(argv[0],argv); exit(1); } int status=0; pid_t rid=waitpid(id,&status,0); if(rid<0) { //等待失败 } else { return true; } return false;
}
哪些命令可以让子进程执行,哪些命令不能让子进程执行?为什么?
让shell去执行的命令,叫做内键命令。
当执行cd命令时,为什么pwd没有改变?
我们写的超简易版shell中,让子进程去执行cd .. 。但是其他的进程不是由子进程产生的,不会继承子进程的环境变量,还是去继承父进程的环境变量。虽然在子进程中改了环境变量,但是没有得到进程,所以不起作用。在真正的shell中,就是要去改变shell的环境变量。因为其他的进程都是bash的子进程。
通过getcwd获取实时的cwd,通过putenv导入环境变量:
//获取当前路径信息
string GetPWD()
{if(nullptr==getcwd(cwd,sizeof(cwd)))return "None";snprintf(pwdenv,sizeof(pwdenv),"PWD=%s",cwd);//更新envputenv(pwdenv);return cwd;
}

myshell维护自己的环境变量:
环境变量和本地变量是存在于shell中的一个表。这两张表就是全局的char*数组。指向很多的字符串。后序我们碰见要导入环境变量的命令,我们直接在shell中的genv数组指向一个堆空间,然后把第一个为空的数组指向这个字符串。
为什么要新申请空间,然后拷贝,再指向?
因为我们每执行一个命令,argv都是会变化的。如果我们直接让genv的元素指向argv的元素,以后会发生变化。这样环境变量就找不到了。
相关文章:
【Linux课程学习】:《简易版shell实现和原理》 《哪些命令可以让子进程执行,哪些命令让shell执行(内键命令)?为什么?》
🎁个人主页:我们的五年 🔍系列专栏:Linux课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 打印命令行提示符(PrintCommandLin…...
2024年11月27日Github流行趋势
项目名称:screenshot-to-code 项目维护者:abi clean99 sweep-ai kachbit vagusX项目介绍:通过上传截图将其转换为整洁的代码(支持HTML/Tailwind/React/Vue)。项目star数:62,429项目fork数:7,614…...
Java中的线程池使用详解
文章目录 Java中的线程池使用详解一、引言二、线程池的创建与使用1、线程池的创建1.1、FixedThreadPool(固定大小线程池)1.2、CachedThreadPool(可缓存线程池)1.3、SingleThreadExecutor(单线程化线程池)1.…...
Redis(概念、IO模型、多路选择算法、安装和启停)
一、概念 关系型数据库是典型的行存储数据库,存在的问题是,按行存储的数据在物理层面占用的是连续存储空间,不适合海量数据存储。 Redis在生产中使用的最多的是用作数据缓存。 服务器先在缓存中查询数据,查到则返回,…...
计算机网络 第4章 网络层
计算机网络 (第八版)谢希仁 第 4 章 网络层4.2.2 IP地址**无分类编址CIDR**IP地址的特点 4.2.3 IP地址与MAC地址4.2.4 ARP 地址解析协议4.2.5 IP数据报的格式题目2:IP数据报分片与重组题目:计算IP数据报的首部校验和(不正确未改) …...
Java学习笔记--继承方法的重写介绍,重写方法的注意事项,方法重写的使用场景,super和this
目录 一,方法的重写 二,重写方法的注意事项 三,方法重写的使用场景 四,super和this 1.继承中构造方法的特点 2.super和this的具体使用 super的具体使用 this的具体使用 一,方法的重写 1.概述:子类中有一个和父类…...
高级java每日一道面试题-2024年11月27日-JVM篇-JVM的永久代中会发生垃圾回收么?
如果有遗漏,评论区告诉我进行补充 面试官: JVM的永久代中会发生垃圾回收么? 我回答: 在Java虚拟机(JVM)的历史版本中,确实存在一个称为“永久代”(Permanent Generation, 或者简称PermGen)的内存区域。永久代主要用…...
Spring Boot教程之十: 使用 Spring Boot 实现从数据库动态下拉列表
使用 Spring Boot 实现从数据库动态下拉列表 动态下拉列表(或依赖下拉列表)的概念令人兴奋,但编写起来却颇具挑战性。动态下拉列表意味着一个下拉列表中的值依赖于前一个下拉列表中选择的值。一个简单的例子是三个下拉框,分别显示…...
基于混合ABC和A*算法复现
基于混合ABC和A*算法复现 一、背景介绍二、算法原理(一)A*算法原理(二)人工蜂群算法原理(三)混合ABC和A*算法策略 三、代码实现(一)数据准备(二)关键函数实现…...
狂野飙车8+(Asphalt 8+) for Mac 赛车竞速游戏 安装教程
Mac分享吧 文章目录 狂野飙车8(Asphalt 8) for Mac 赛车竞速游戏软件 效果图展示一、狂野飙车8(Asphalt 8) 赛车竞速游戏 Mac电脑版——v2.1.11️⃣:下载软件2️⃣:安装软件2.1 左侧安装包拖入右侧文件夹中,等待安装完成,运行软件…...
网络技术-VRRP(虚拟路由冗余协议)部署介绍
一、VRRP的含义 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)是一种高度可靠的路由器备用协议,用于在局域网内部提供路由器冗余。 其部署方式主要是通过多个路由器组成一个虚拟路由器组,通过协议选…...
C语言解决空瓶换水问题:高效算法与实现
标题:C语言解决空瓶换水问题:高效算法与实现 一、问题描述 在一个饮料促销活动中,你可以通过空瓶换水的方式免费获得更多的水:3个空瓶可以换1瓶水。喝完这瓶水后,空瓶会再次变为空瓶。假设你最初拥有一定数量的空瓶&a…...
day2全局注册
全局注册代码: //文件核心作用:导入App.vue,基于App.vue创建结构渲染index.htmlimport Vue from vue import App from ./App.vue //编写导入的代码,往代码的顶部编写(规范) import HmButton from ./components/Hm-But…...
鸿蒙多线程应用-taskPool
并发模型 并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。 Actor并发模型作为基于消息通信并发模型的典型代表,不需要开发者去面对锁带来的一系列复杂偶发的问题,同…...
【失败经验】将算法模型封装为安卓应用
背景:不懂安卓开发,希望能使用大模型编码完成安卓应用生成,调用算法模型进行预测。 模型准备: pip方案安装pcnn; 然后需要将pytorch训练完成的算法模型保存为torchscript模型,然后使用pcnn转换为ncnn的模…...
ABAP OOALV模板
自用模板,可能存在问题 一、主程序 *&---------------------------------------------------------------------* *& Report ZVIA_OO_ALV *&---------------------------------------------------------------------* REPORT ZVIA_OO_ALV.INCLUDE ZVI…...
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-autobatch.py
autobatch.py ultralytics\utils\autobatch.py 目录 autobatch.py 1.所需的库和模块 2.def check_train_batch_size(model, imgsz640, ampTrue, batch-1): 3.def autobatch(model, imgsz640, fraction0.60, batch_sizeDEFAULT_CFG.batch): 1.所需的库和模块 # Ultraly…...
SycoTec 4060 ER-S德国高精密主轴电机如何支持模具的自动化加工?
SycoTec 4060 ER-S高速电主轴在模具自动化加工中的支持体现在以下几个关键方面: 1.高精度与稳定性:SycoTec 4060 ER-S锥面跳动小于1微米,确保了加工过程中的极高精度,这对于模具的复杂几何形状和严格公差要求至关重要。高精度加工…...
部署 DeepSpeed以推理 defog/sqlcoder-70b-alpha 模型
部署 DeepSpeed 以推理 defog/sqlcoder-70b-alpha 这样的 70B 模型是一个复杂的过程,涉及多个关键步骤。下面是详细的步骤,涵盖了从模型加载、内存优化到加速推理的全过程。 1. 准备环境 确保你的环境配置正确,以便能够顺利部署 defog/sqlc…...
Python网络爬虫基础
Python网络爬虫是一种自动化工具,用于从互联网上抓取信息。它通过模拟人类浏览网页的行为,自动地访问网站并提取所需的数据。网络爬虫在数据挖掘、搜索引擎优化、市场研究等多个领域都有广泛的应用。以下是Python网络爬虫的一些基本概念: 1.…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
SpringCloud优势
目录 完善的微服务支持 高可用性和容错性 灵活的配置管理 强大的服务网关 分布式追踪能力 丰富的社区生态 易于与其他技术栈集成 完善的微服务支持 Spring Cloud 提供了一整套工具和组件来支持微服务架构的开发,包括服务注册与发现、负载均衡、断路器、配置管理等功能…...
