【Linux】自己实现一个bash进程
bash就是命令行解释器,就是Linux操作系统让我们看到的,与用户进行交互的一种外壳(shell),当然了bash也是一个进程,它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进程程序替换,就是让子进程去替换我们的命令进程,知道了它的原理,我们就可以试着自己写一个bash进程。
我们可以大体上对于整个过程来细分一下:
1.bash就是先打印命令行提示符,就是下面这个东西,获取用户输入的命令
命令行提示符由 [用户名@主机名 路径]# 这些构成
2.对于用户输入的字符串进行分割成命令
3.执行这个命令
其实大体上就是这三步,下面还有很多的细节问题,我们遇到再说

我们目前写的这个代码的结果是

为什么打印了两个换行?我们了解一下fgets这个函数

因为fgets会读入一个换行,就是我们敲完abc后的换行,它是不应该有的,我们要给它去掉

这样就可以把换行改成0了。
因为bash就是一只在等待用户输入指令,所以我们要把我们的程序写成一个循环。
还有一个问题,就是当我们什么都不输入,直接回车时,我们其实就没必要在执行下边了,直接回到循环最开始就可以,于是我们可以做一个判断就是如果输入的命令的长度为0,那么就直接回到循环最开始处,这里的长度可以让Interactive的返回值来给。
下一步就是对于字符串进行分割:
我们分割的话,函数可以将收到的字符串分割后放到一个全局变量中,方便后续的使用,我们C语言有一个分割字符串的函数,叫strtok

分割完了之后,我们就可以开始执行命令了,就是让子进程执行,父进程等待。我们这里先是一些普通的需要子进程去执行的命令,因为有的命令需要父进程去执行,比如cd,需要父进程去切换路径,子进程是不行的

那么截止到现在,我们的程序已经可以像bash一样处理一些命令了,但是还不够,因为有一些内建命令,就是需要父进程去执行的:

这些命令,我们要在代码被子进程执行前先行判断,如果是内建命令,那么让父进程去执行,否则再让子进程去执行
我们这里先以cd命令为例,如果判断出来了用户就是要输入cd命令,如果后边什么都没有,那么默认是回到家目录,如果有,那就chdir到那个目录,并且不要忘记命令行提示符可是一直通过环境变量PWD来打印我们当前所在目录的,所以我们还要通过putenv把PWD环境变量改一下,它默认是会覆盖的。
之后我们要知道export也是一个内建命令,export的作用是给自己设置一个环境变量,如果给子进程设置,那显然是不合理的,所以我们也需要处理一下。
下一个就是echo,我们的echo通常会有这么几种用法:
1.echo后什么都不加
2.后加$?表示打印最近一次进程的退出码
3.后随便打印一串字符
4.后加$环境变量,就打印环境变量的内容

下面是所有的代码,有不足的可以添加:
1 #define _XOPEN_SOURCE 2 #include<stdio.h>3 #include<stdlib.h>4 #include<string.h>5 #include<unistd.h>6 #include<sys/types.h>7 #include<sys/wait.h>8 #include<stdlib.h>9 #define SIZE 102410 #define MAX_ARGC 30//最大命令行字符串个数11 #define SEP " "//设置分隔符为空格12 char*argv[MAX_ARGC];13 int lastcode;//最近一次进程退出码14 int Interactive(char commandline[],int size)15 {16 printf("[%s@%s %s]$ ",getenv("USER"),getenv("HOSTNAME"),getenv("PWD"));17 fgets(commandline,size,stdin);18 commandline[strlen(commandline)-1]='\0';19 return strlen(commandline);20 }21 void Splitstr(char commandline[])22 {23 int i=0;24 argv[i++]=strtok(commandline,SEP);25 while(argv[i++]=strtok(NULL,SEP));26 if(strcmp("ls",argv[0])==0)27 {28 argv[i-1]="--color";29 argv[i]=NULL;30 }31 }32 void Execute()33 { 34 if(strcmp("ll",argv[0])==0&&!argv[1])//特别处理ll35 {36 argv[0]="ls";37 argv[1]="-l";38 }39 pid_t id=fork();40 if(id==0)41 {42 execvp(argv[0],argv);43 printf("mybash: ");44 for(int i=0;argv[i];i++)printf("%s ",argv[i]);45 printf(": not found your command\n");46 exit(2);47 }48 int status=0;49 pid_t rid=waitpid(id,&status,0);50 if(rid>0)lastcode=WEXITSTATUS(status);51 }52 int Bulidincmd()53 {54 int ret=0;55 if(strcmp("cd",argv[0])==0)56 {57 ret=1;58 char*target=argv[1];59 if(!target)target=getenv("HOME");60 chdir(target);61 char tmp[SIZE];62 snprintf(tmp,SIZE,"PWD=%s",target);63 putenv(tmp); 64 }65 else if(strcmp("export",argv[0])==0)66 {67 ret=1;68 if(argv[1])69 {70 char tmp[SIZE];71 strncpy(tmp,argv[1]+1,strlen(argv[1])-2);72 putenv(tmp);73 }74 }75 else if(strcmp("echo",argv[0])==0)76 {77 ret=1;78 if(argv[1]&&argv[1][0]=='$')79 {80 if(argv[1][1]=='?'&&!argv[2])81 {82 printf("%d\n",lastcode);83 lastcode=0;84 }85 else86 {87 char* tmp=getenv(argv[1]+1); 88 if(tmp)printf("%s\n",tmp);89 }90 }91 else92 {93 for(int i=1;argv[i];i++)printf("%s ",argv[i]);94 printf("\n");95 }96 }97 lastcode=0;98 return ret;99 }100 int main()101 {102 while(1)103 {104 char commandline[SIZE];105 //打印命令行提示符,获取用户输入的命令字符串106 int n=Interactive(commandline,SIZE);107 if(n==0)continue;108 //分割字符串成命令行参数109 Splitstr(commandline);110 //处理内建命令111 n=Bulidincmd();112 if(n==1)continue;113 //执行命令114 Execute(); 115 }116 return 0;117 }
相关文章:
【Linux】自己实现一个bash进程
bash就是命令行解释器,就是Linux操作系统让我们看到的,与用户进行交互的一种外壳(shell),当然了bash也是一个进程,它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进…...
记录深度学习GPU配置,下载CUDA与cuDnn
目标下载: cuda 11.0.1_451.22 win10.exe cudnn-11.0-windows-x64-v8.0.2.39.zip cuda历史版本网址 CUDA Toolkit Archive | NVIDIA Developer 自己下载过11.0.1版本 点击下载local版本,本地安装,有2个多GB,很大,我不喜欢network版本,容易掉线 cuDnn https://developer.nvi…...
Word将表格调成合适的大小
请等待内容完善...
2024HBCPC:C Goose Goose Duck
题目描述 Iris 有 n n n 个喜欢玩鹅鸭杀的朋友,编号为 1 ∼ n 1∼n 1∼n。 假期的时候,大家经常会在群里问有没有人玩鹅鸭杀,并且报出现在已经参与的人数。 但是每个人对于当前是否加入游戏都有自己的想法。 具体的来说,对于第…...
Llama 3 模型家族构建安全可信赖企业级AI应用之使用 Llama Guard 保护大模型对话 (八)
LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 (一) 基于 LlaMA 3 LangGraph 在windows本地部署大模型 (二) 基于 LlaMA 3 LangGraph 在windows本地部署大模型 (三) 基于 LlaMA…...
《一地霜白》读书笔记
1.3.6 街灯明灭,勾缀成行,为了生者与死者 “很多年过去了。回头看,沿着一排暗中的街灯,两三盏灭了,郁闷中有意外的欣喜:街灯明灭,勾缀成行,为了生者与死者。” 童年、青少年在人的…...
在Java中实现多线程之间的通信
一、技术难点 在Java中实现多线程之间的通信是一个复杂但重要的任务,它涉及到线程同步、数据共享和线程间协作等多个方面。以下是实现多线程通信时可能遇到的一些技术难点: 线程同步:多线程环境下,多个线程可能同时访问和修改共享…...
Python中的json.dump与json.dumps对比
Python中的json.dump与json.dumps对比 json.dumps()json.dump() json.dumps() dumps 是 “dump string” 的缩写。它将Python对象转换(序列化)为JSON格式的字符串。数据被转换为一个字符串,并且这个字符串可以直接被写入文件、发送到网络&am…...
【从零开始学习RabbitMQ | 第二篇】如何确保MQ的可靠性和消费者可靠性
目录 前言: MQ可靠性: 数据持久化: Lazy Queue: 消费者可靠性: 消费者确认机制: 消费失败处理: MQ保证幂等性: 方法一: 总结: 前言: …...
常用批处理命令及批处理文件编写技巧
一常用批处理命令 1.查看命令用法:命令 /? //如:cd /? 2.切换盘符目录:cd /d D:\test 或直接输入 d: //进入上次d盘所在的目录 3.切换目录:cd test 4.清屏:cls 5.“arp -a” //它会列出当前设备缓存中的所有…...
android NetworkMonitor记录
是否能上网的状态 上网url地址的设置: NetworkMonitor.java makeCaptivePortalHttpsUrls config_captive_portal_https_urls DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS http准备监测 isCaptivePortal sendHttpAndHttpsParallelWithFallbackProbes httpsProbe.start();…...
OSPF优化——OSPF减少LSA更新量2
二、特殊区域——优化非骨干区域的LSA数量 不是骨干区域、不能存在虚链路 1、不能存在 ASBR 1)末梢区域 该区域将拒绝 4、5LSA的进人,同时由该区域连接骨干0区域的ABR 向该区域,发布一条3类的缺省路由; 该区域内每台路由器均需配置…...
【AMS】Android 8.0+ 绕开启动后台Service限制
一、背景 应客户要求,需要在开机时,拉起应用A。但因为开机时,同时被拉起的应用过多,导致Launcher在开机那一刻较为卡顿。为解决这一问题,采取了延迟拉起的做法。在开机后,延迟一定时间,由系统服务,拉起应用A。 于是乎,就出现这么个报错: Not allowed to start ser…...
【多态】(超级详细!)
【多态】(超级详细!) 前言一、 多态的概念二、重写1. 方法重写的规则2. 重写和重载的区别 三、多态实现的条件四、 向上转型五、动态绑定 前言 面向对象的三大特征:封装性、继承性、多态性。 extends继承或者implements实现&…...
vue的组件化
vue的组件化 vue的组件化,就是根据功能、业务逻辑、数据流向等因素进行划分把页面拆分成多个组件。组件是资源独立的,组件也可以相互嵌套。目的是提高代码的可读性、可维护性和可复用性。 组件化思想体现 组件封装步骤 1.公共组件 公共组件全局注…...
spark的简单学习一
一 RDD 1.1 RDD的概述 1.RDD(Resilient Distributed Dataset,弹性分布式数据集)是Apache Spark中的一个核心概念。它是Spark中用于表示不可变、可分区、里面的元素可并行计算的集合。RDD提供了一种高度受限的共享内存模型,即RD…...
【第5章】SpringBoot整合Druid
文章目录 前言一、启动器二、配置1.JDBC 配置2.连接池配置3. 监控配置 三、配置多数据源1. 添加配置2. 创建数据源 四、配置 Filter1. 配置Filter2. 可配置的Filter 五、获取 Druid 的监控数据六、案例1. 问题2. 引入库3. 配置4. 配置类5. 测试类6. 测试结果 七、案例 ( 推荐 )…...
力扣654. 最大二叉树
Problem: 654. 最大二叉树 文章目录 题目描述思路复杂度Code 题目描述 思路 对于构造二叉树这类问题一般都是利用先、中、后序遍历,再将原始问题分解得出结果 1.定义递归函数build,每次将一个数组中的最大值作为当前子树的根节点构造二叉树;…...
基于Netty实现WebSocket客户端
本文是基于Netty快速上手WebSocket客户端,不涉及WebSocket的TLS/SSL加密传输。 WebSocket原理参考【WebSocket简介-CSDN博客】,测试用的WebSocket服务端也是用Netty实现的,参考【基于Netty实现WebSocket服务端-CSDN博客】 一、基于Netty快速…...
homebrew安装mysql的一些问题
本文目录 一、Homebrew镜像安装二、mac安装mysql2.1、修改mysql密码 本文基于mac环境下进行的安装 一、Homebrew镜像安装 Homebrew国内如何自动安装,运行命令/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 会…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
stm32进入Infinite_Loop原因(因为有系统中断函数未自定义实现)
这是系统中断服务程序的默认处理汇编函数,如果我们没有定义实现某个中断函数,那么当stm32产生了该中断时,就会默认跑这里来了,所以我们打开了什么中断,一定要记得实现对应的系统中断函数,否则会进来一直循环…...
