【Linux】自主shell编写

如果学习了常见的Linux命令,exec*函数,环境变量,那你就可以尝试一下写一个简单的shell;

下面跟着我的步骤来吧!!🤩🤩

输入命令行

既然要写一个shell,我们第一步先把这个输入命令行打印出来:

观察一下:命令行中有三个环境变量,我们如何查找它们呢?

这就需要使用env查找:发现USER、HOSTNAME、PWD;

 怎么用代码来获取这三个环境变量对应的值呢?

用:getenv函数

有关函数更详细的内容可以区man手册上区查看

接下来,我们就可以写代码了:(主要代码,完整代码在文章最后)

  void Makecommandline(){char cmd[SIZE];const char *name=Getname();const char *hostname = Gethostname();const char *cwd =Getcwd();snprintf(cmd,sizeof(cmd),"[%s@%s %s]> ",name,hostname,cwd);printf("%s",cmd);fflush(stdout);}

获取用户命令

想一下,我们输入一个命令时,有时候是ls,有时候是ls -l -a ,输入的有空格怎么办呢?🤖

这时就可以用fgets函数来输入命令;

 void Getusercommand(char Usercmd[]){char *s = fgets(Usercmd,sizeof(Usercmd),stdin);if(s==NULL){perror("fgets");exit(1);}Usercmd[strlen(Usercmd)-1]='\0';}

命令行字符串分割

获取到用户命令后,接下来我们要对这个命令进行分割:

分割用的是strtok函数;

代码:

void Splitcommand(char Usercmd[]){argv[0]=strtok(Usercmd,SEP);int index=1;while(argv[index++]=strtok(NULL,SEP));}

执行命令

完成上述的准备工作后,我们要执行我们输入的命令,那要怎么执行呢?

🤡当然是用的我们的exec*函数喽,这里根据实际情况,我们选择的应该是execvp()函数;

💥💥注意:我们使用exec*函数时,要创建一个子进程来进行,这样才不会使父进程中后续代码被覆盖!!

代码:

void Executecommand(){pid_t id =fork();if(id<0){exit(1);}else if(id==0){execvp(argv[0],argv);exit(errno);}else{int status=0;pid_t rid =waitpid(id,&status,0);if(rid>0){//wait sucesslastcode = WEXITSTATUS(status);if(lastcode!=0){printf("%s:%s:%d\n",argv[0],strerror(lastcode),lastcode);}}}}

检测命令是否是内建命令

😺😺完成上述的四部后,你就已经完成了一个简单的shell,但是并不完整;哪里不完整呢?我们可以输入一个内建命令,比如cd命令,这时我们就找到了要完善的地方;

怎么完善呢?

我们要判断一下这个命令是不是内建命令,怎么判断呢,非常简单,直接if语句:

如果有其他的内建命令,直接添加即可;

Cd():如果是内建cd命令,看一下argv[1]是不是空,

(1)如果是空,我们输入的命令就是cd,那不就是直接回到家目录了嘛,如果不为空,就不要变了;

(2)接下来,直接改变cwd即可,用chdir函数;

(3)修改环境变量PWD的值,用putenv函数;

💥💥注意:putenv 用于将一个字符串添加到环境变量中,或者修改已经存在的环境变量。这个字符串的格式通常是 "NAME=VALUE",其中 NAME 是环境变量的名称,VALUE 是其对应的值。

你已经完成了一个基础的shell,更完善的shell还会继续更新!!

完整代码:

  1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 #include<string.h>5 #include<sys/types.h>6 #include<sys/wait.h>7 #include<errno.h>8 9 # define SkipPath(p) do{p+=(strlen(p)-1);while(*p!='/')p--;}while(0)10 11 12 #define SIZE 51213 #define SEP " "14 15 16 char cwd[SIZE*2];17 int lastcode =0;18 char *argv[SIZE*2];19 20 const char *Getname()21 {22     const char *name=getenv("USER");23     if(name==NULL)return "None";24     return name;25 }26 27 28 const char *Gethostname()29 {30     const char *hostname=getenv("HOSTNAME");31     if(hostname==NULL)return "None";32     return hostname;33 }34 35 36 const char *Getcwd()37 {38     const char *pwd=getenv("PWD");39     if(pwd==NULL)return "None";40     return pwd;41 }42 43 void Makecommandline()44 {45     char cmd[SIZE];46     const char *name=Getname();47     const char *hostname = Gethostname();48     const char *cwd =Getcwd();49     SkipPath(cwd);50     snprintf(cmd,sizeof(cmd),"[%s@%s %s]> ",name,hostname,strlen(cwd)==1 ? "/":cwd+1);51     printf("%s",cmd);52     fflush(stdout);53 }54 55 void Getusercommand(char Usercmd[])56 {57     char *s = fgets(Usercmd,sizeof(Usercmd),stdin);58     if(s==NULL)59     {60         perror("fgets");61         exit(1);62     }63     Usercmd[strlen(Usercmd)-1]='\0';64 }65 66 void Splitcommand(char Usercmd[])67 {68     argv[0]=strtok(Usercmd,SEP);69     int index=1;70     while(argv[index++]=strtok(NULL,SEP));71 }72 const char *Gethome()73 {74     const char *home =getenv("HOME");75     if(home==NULL)return "/root";76     return home;77 }78 void Cd()79 {80     const char *path =argv[1];81     if(path==NULL)82     {83         //返回家目录84         path = Gethome();85     }86     chdir(path);87     char tmp[SIZE*2];88     getcwd(tmp,sizeof(tmp));89     snprintf(cwd,sizeof(cwd),"PWD=%s",tmp);90     putenv(cwd);91     //printf("%s\n",cwd);92 }93 int Checkbuildin()94 {95     int yes=0;96     if(strcmp(argv[0],"cd")==0)97     {98         yes=1;99         Cd();
100     }
101     return yes;
102 }
103 void Executecommand()
104 {
105     pid_t id =fork();
106     if(id<0)
107     {
108         exit(1);
109     }
110     else if(id==0)
111     {
112         execvp(argv[0],argv);
113         exit(errno);
114     }
115     else
116     {
117         int status=0;
118         pid_t rid =waitpid(id,&status,0);
119         if(rid>0)
120         {
121             //wait sucess
122             lastcode = WEXITSTATUS(status);
123             if(lastcode!=0)
124             {
125                 printf("%s:%s:%d\n",argv[0],strerror(lastcode),lastcode);
126             }
127         }
128     }
129 }
130 int main()
131 {
132     while(1)
133     {
134         //1、我们自己输入一个命令行
135         Makecommandline();
136 
137         //2、获取用户命令字符串分割
138         char Usercmd[SIZE];
139         Getusercommand(Usercmd);
140         //printf("%s\n",Usercmd);
141         //3、命令行字符串分割
142         Splitcommand(Usercmd);
143         //4、检测命令是否是内建命令
144         int n = Checkbuildin();
145         if(n)continue;
146         //5、执行命令
147         Executecommand();
148     }
149     return 0;
150 }

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java中数组的应用

Java中数组的应用 数组数组的使用使用方式1-动态初始化数组的定义&#xff1a;数组的引用&#xff08;使用/访问/获取数组元素&#xff09;&#xff1a;快速入门案例 使用方式2-动态初始化**先声明**数组**再创建**数组使用方式1和2的比较 使用方式3-静态初始化初始化数组快速入…

【AI知识点】残差网络(ResNet,Residual Networks)

残差网络&#xff08;ResNet&#xff0c;Residual Networks&#xff09; 是由微软研究院的何凯明等人在 2015 年提出的一种深度神经网络架构&#xff0c;在深度学习领域取得了巨大的成功。它通过引入残差连接&#xff08;Residual Connection&#xff09; 解决了深层神经网络中…

数学公式编辑器免费版下载,mathtype和latex哪个好用

选择适合自己的公式编辑器需要考虑多个因素。首先&#xff0c;您需要确定编辑器支持的功能和格式是否符合您的需求&#xff0c;例如是否可以插入图片、导出各种文件格式等。其次&#xff0c;您可以考虑编辑器的易用性和界面设计是否符合您的个人喜好。另外&#xff0c;您还可以…

蓝桥杯【物联网】零基础到国奖之路:十八. 扩展模块之光敏和AS312

蓝桥杯【物联网】零基础到国奖之路:十八.扩展模块之光敏和AS312 第一节 硬件解读第二节 CubeMX配置第二节 代码 第一节 硬件解读 光敏和AS312如下图&#xff1a; 光敏电阻接到了扩展模块的5号引脚&#xff0c;5号引脚接了2个电阻&#xff0c;R8和光敏电阻。我们通过ADC读取这…

Excel实现省-市-区/县级联

数据准备 准备省份-城市映射数据&#xff0c;如下&#xff1a; 新建sheet页&#xff0c;命名为&#xff1a;省-市数据源&#xff0c;然后准备数据&#xff0c;如下所示&#xff1a; 准备城市-区|县映射数据&#xff0c;如下&#xff1a; 新建sheet页&#xff0c;命名为&#x…

C语言的柔性数组

目录 柔性数组1.柔性数组的特点&#xff1a;2.柔性数组的使用3.柔性数组的优势 柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff0c;结构体中的最后⼀个元素允许是未知⼤⼩的数组&…

分治算法(2)_快速排序_排序数组

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(2)_快速排序_排序数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

消息称苹果iPhone系列将完全放弃LCD屏幕

近日&#xff0c;据日经亚洲消息&#xff0c;苹果公司将于明年初推出搭载OLED显示屏的 iPhone SE 4&#xff0c;标志其整个iPhone系列已进入从 LCD 过渡到 OLED 技术的最后阶段&#xff0c;2025年及之后销售的所有iPhone机型均将搭载OLED屏幕。 由此&#xff0c;两家日本面板供…

【STM32开发环境搭建】-4-在STM32CubeMX中新增Keil(MDK-ARM) 5的工程目录(包含指定路径的C和H文件)

案例背景&#xff1a; 由于Keil(MDK-ARM)5工程&#xff1a;DEMO_STM32F030C8T6.uvprojx是由STM32CubeMX工具生成的&#xff0c;如果我们在Keil工程中手动添加了一些c文件和h文件的Include Path包含路径&#xff0c;会在STM32CubeMX下一次生成uvprojx文件时&#xff0c;被删除&…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【272-284】

272. 包基本介绍 272.1 看一个应用场景 272.2 包的三大作用 272.3 包的基本语法 273. 包原理 274. 包快速入门 在不同的包下面创建不同的Dog类 275. 包命名 276. 常用的包 一个包下,包含很多的类,java 中常用的包有: java.lang.* //lang 包是基本包&#xff0c;默认引入&…

hdfs伪分布式集群搭建

1 准备 vmware 虚拟三台centos系统的节点三台机器安装好jdk环境关闭防火墙&#xff08;端口太多&#xff0c;需要的自行去开关端口&#xff09;hadoop压缩包解压至三台服务器 可在一台节点上配置完成后克隆为三台节点 2 host修改 vi /etc/hosts在每个节点上添加三台机器的i…

linux部署NFS和autofs自动挂载

目录 &#xff08;一&#xff09;NFS&#xff1a; 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…

求矩阵的鞍点

题目&#xff1a;求一个矩阵的鞍点&#xff0c;即行上最小而列上最大的元素。 代码&#xff1a;&#xff08;多个最小值认为第一个为最小&#xff0c;更严谨的代码在最后&#xff09; #include<iostream> #include<time.h> using namespace std;int main(){int n…

【Qt】控件概述(7)—— 布局管理器

布局管理器 1. 布局管理器2. QVBoxLayout——垂直布局3. QHBoxLayout——水平布局4. QGridLayout——网格布局5. QFormLayout——表单布局6. QSpacer 1. 布局管理器 在我们之前值ui界面进行拖拽设置控件时&#xff0c;都是通过手动的控制控件的位置的。同时每个控件的位置都是…

贪心算法c++

贪心算法C概述 一、贪心算法的基本概念 贪心算法&#xff08;Greedy Algorithm&#xff09;&#xff0c;又名贪婪法&#xff0c;是一种解决优化问题的常用算法。其基本思想是在问题的每个决策阶段&#xff0c;都选择当前看起来最优的选择&#xff0c;即贪心地做出局部最优的决…

实验OSPF路由协议(课内实验)

实验1&#xff1a;OSPF路由协议 实验目的及要求&#xff1a; 通过实验&#xff0c;能够理解链路状态型路由协议OSPF协议的工作原理&#xff0c;掌握如何实现单区域 OSPFv2配置指令&#xff0c;能够熟练的应用各种OSPF协议相关的配置指令完善网络设计。掌握验证OSPFv2网络连接…

Linux启动mysql报错

甲方公司意外停电&#xff0c;所有服务器重启后&#xff0c;发现部署在Linux上的mysql数据库启动失败.再加上老员工离职&#xff0c;新接手项目&#xff0c;对Linux系统了解不多&#xff0c;解决起来用时较多&#xff0c;特此记录。 1.启动及报错 1.1 启动语句1 启动语句1&a…

利用 OpenAI 和 Python 预测股市行情

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 本文介绍了如何利用 OpenAI 和 Python 进行股市情绪预测。主要通过使用 EODHD 提供的股市和金融新闻 API 来提取新闻数据,并利用 LangChain 和 OpenAI 的大型语言模型进行情感分析。 一、综述 …

Eureka的搭建、注册和拉取

目录 搭建 动手实践 搭建EurekaServer 创建项目 编写启动类 添加application.yml文件 启动EurekaApplication ​编辑 总结 搭建EurekaServer 注册 将user-service服务注册到EurekaServer 将order-service服务注册到EurekaServer 重启order-service和user-service…

将自己写好的项目部署在自己的云服务器上

准备工作 这里呢我要下载的终端软件是Xshell 如图&#xff1a; 自己准备好服务器&#xff0c;我这里的是阿里云的服务器&#xff0c; 如图&#xff1a; 这两个准备好之后呢&#xff0c;然后对我们的项目进行打包。 如图&#xff1a; 这里双击打包就行了。 找到自己打成jar包…