【linux】自主shell编写

Alt

🔥个人主页Quitecoder

🔥专栏linux笔记仓

Alt

目录

    • 01.输出命令行
    • 02.获取用户命令字符串
    • 03.命令行字符串分割
    • 04.执行命令
    • 05.细节修改
      • 检查是否为内建命令
    • 完整代码:

01.输出命令行

完成对一个shell 的编写,首先我们需要输出一个自己的命令行

在这里插入图片描述
我们可以通过getenv来获取环境变量

const char * GetSserName()
{const char *name = getenv("USER");if(name == NULL) return "None";return name;
}

用getnev来获取USER

在这里插入图片描述
拿到用户名后,第二个获取主机名

const char * GetHostName()
{const char *hostname = getenv("HOSTNAME");if(hostname==NULL) return "None";return hostname;
}

接着我们获取路路径,这里先写一个不规范的路径版本:

const char * GetCwd()
{const char *cwd = getenv("PWD");if(cwd == NULL ) return "None";return cwd;
}

在这里插入图片描述

后面我们再对路径进行截取

在这里插入图片描述
现在完成对命令行输出的编写,我们目标是将变量名放到一个输出型参数commandline中,这里需要一个函数snprintf:
在这里插入图片描述

void MakeCommandLine(char line[],size_t size)
{const char* username= GetUserName();const char* hostname= GetHostName();const char* cwd= GetCwd();snprintf(line,size,"[%s@%s %s]> ",username,hostname,cwd);printf("%s",line);fflush(stdout);
}

这就完成了命令行输出部分的函数,这里打印是向缓冲区打印,我们需要刷新缓冲区

02.获取用户命令字符串

用户输入的各种指令,本质就是一个字符串,我们要做的就是对字符串进行截取并且按照要求完成内容输出

我们这里不能直接用scanf来获取,因为这里scanf的分隔符为空格,我们这里想按照行来拿字符串,用fgets

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们这里将输入的回车\n改为\0;

在这里插入图片描述
我们向usercommand这个缓冲区输入来获取命令

03.命令行字符串分割

在这里插入图片描述

这里定义全局的存储各个命令的字符串数组,用strtok进行分割,注意!:这里strtok的第二个参数是const char *类型的,一定是一个字符串
在这里插入图片描述
所以我们这里定义的分隔符必须是字符串

在这里插入图片描述
这里写成=,表示先赋值,再判断,分割之后,strtok会返回NULL,刚好让gArgv最后一个元素是NULL,并且while判断结束

检验结果:
在这里插入图片描述

04.执行命令

执行命令,我们创建子进程进行程序替换

在这里插入图片描述
在这里插入图片描述
我们将上面的代码放入一个新函数中,并让上面的过程持续进行:

在这里插入图片描述
在这里插入图片描述

05.细节修改

在这里插入图片描述

我们发现现在,执行cd命令是没有反应的

自定义 shell 无法运行 cd 指令的原因主要是因为 cd 是一个 内建命令,它不会创建新进程,而是直接改变当前进程的工作目录。因此,简单地使用 fork()execvp() 来执行 cd 是不行的,因为 cd在子进程内生效,但子进程在执行完命令后会终止,所以父进程的工作目录不会改变。

在当前的代码中,所有的命令都会通过 fork() 创建子进程,并在子进程内使用 execvp() 执行。这种方法适用于外部命令,但对 cd 这样的内建命令并不适用


要让 cd 命令能够正确工作,需要在父进程中执行 cd 操作,而不是在子进程中。可以通过检查用户输入的命令是否为 cd,如果是 cd,则在父进程中直接使用 chdir() 系统调用来改变当前工作目录。

检查是否为内建命令

const char * GetHome()
{const char *home=getenv("HOME");if(home== NULL) return "/root";return home;
}void Cd()
{const char *path=gArgv[1];if(path==NULL)path =GetHome();chdir(path);}
int CheckBuildin()
{int yes=0;const char * enter_cmd= gArgv[0];if(strcmp("cd",enter_cmd)==0){yes=1;Cd();}return yes;
}
int main()
{int quit=0;while(!quit){//1.输出命令行MakeCommandLine();//2.获取输入命令char usercommand[SIZE];int n=  GetUserCommand(usercommand,sizeof(usercommand));if(n<=0) return 1;//3.命令行字符串分割SplitCommand(usercommand,sizeof(usercommand));  //4.检查是否为内建命令;n=CheckBuildin();if(n)continue;//执行命令ExecuteCommand();}return 0;}

在这里插入图片描述
现在cd命令可以使用,但是环境变量还是有问题,还需要修改

char cwd[SIZE*2];void Cd()
{const char *path=gArgv[1];if(path==NULL)path =GetHome();chdir(path);snprintf(cwd,sizeof(cwd),"PWD=%s",path);putenv(cwd);
}
int CheckBuildin()
{int yes=0;const char * enter_cmd= gArgv[0];if(strcmp("cd",enter_cmd)==0){yes=1;Cd();}return yes;
}

在这里插入图片描述

void Cd()
{const char *path=gArgv[1];if(path==NULL)path =GetHome();chdir(path);//刷新环境变量char temp[SIZE*2];getcwd(temp,sizeof(temp));snprintf(cwd,sizeof(cwd),"PWD=%s",temp);                                                                                    putenv(cwd);                     
}   

在这里插入图片描述
还需要更改的是,系统的shell只会显示当前路径,而我们自定义的shell会显示绝对路径

在这里插入图片描述

#define SkipPath(p) do{ p+= strlen(p)-1;   while(*p!='/')p--;\
}while(0)void MakeCommandLine()
{char line[SIZE];const char* username= GetUserName();const char* hostname= GetHostName();const char* cwd= GetCwd();SkipPath(cwd);snprintf(line,sizeof(line),"[%s@%s %s]> ",username,hostname,strlen(cwd)==1?"/":cwd+1);printf("%s",line);fflush(stdout);
}

在这里插入图片描述
最后加上退出码

int lastnode=0;
void ExecuteCommand()
{pid_t id=fork();if(id < 0)exit(1);else if(id == 0){execvp(gArgv[0],gArgv);exit(errno);}else {int status=0;pid_t rid = waitpid(id,&status,0);if(rid>0){lastcode=WEXITSTATUS(status);if(lastcode!=0) printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);}}
}int CheckBuildin()                                                               
{                                                                                int yes=0;                                                                   const char * enter_cmd= gArgv[0];                                            if(strcmp("cd",enter_cmd)==0)                                                {                                                                            yes=1;                                                                   Cd();                                                                    }                                                                            else if(strcmp(enter_cmd,"echo")==0&&strcmp(gArgv[1],"$?")==0)               {                                                                            printf("%d\n",lastcode);                                   lastcode=0;                                                                                                             }                                                      return yes;                                            
}  

在这里插入图片描述

完整代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>#define SIZE 512
#define ZERO '\0'
#define SEP " "
#define NUM 32
#define SkipPath(p) do{ p+= strlen(p)-1;   while(*p!='/')p--;\
}while(0)char cwd[SIZE*2];
char *gArgv[NUM];int lastcode=0;const char * GetUserName()
{const char *name = getenv("USER");if(name == NULL) return "None";return name;
}
const char * GetHostName()
{const char *hostname = getenv("HOSTNAME");if(hostname==NULL) return "None";return hostname;
}
const char * GetCwd()
{const char *cwd = getenv("PWD");if(cwd == NULL ) return "None";return cwd;
}
const char * GetHome()
{const char *home=getenv("HOME");if(home== NULL) return "/root";return home;
}
void MakeCommandLine()
{char line[SIZE];const char* username= GetUserName();const char* hostname= GetHostName();const char* cwd= GetCwd();SkipPath(cwd);snprintf(line,sizeof(line),"[%s@%s %s]> ",username,hostname,strlen(cwd)==1?"/":cwd+1);printf("%s",line);fflush(stdout);
}
int GetUserCommand(char command[],size_t n)
{char *s =fgets(command,n,stdin);if(s==NULL) return 1; command[strlen(command)-1]=ZERO;return strlen(command);
}void SplitCommand(char command[],size_t size)
{gArgv[0]=strtok(command,SEP);int index=1;while((gArgv[index++]=strtok(NULL,SEP)));(void)size;
}
void ExecuteCommand()
{pid_t id=fork();if(id < 0)exit(1);else if(id == 0){execvp(gArgv[0],gArgv);exit(errno);}else {int status=0;pid_t rid = waitpid(id,&status,0);if(rid>0){lastcode=WEXITSTATUS(status);if(lastcode!=0) printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);}}
}
void Cd()
{const char *path=gArgv[1];if(path==NULL)path =GetHome();chdir(path);//刷新环境变量char temp[SIZE*2];getcwd(temp,sizeof(temp));snprintf(cwd,sizeof(cwd),"PWD=%s",temp);putenv(cwd);
}
int CheckBuildin()
{int yes=0;const char * enter_cmd= gArgv[0];if(strcmp("cd",enter_cmd)==0){yes=1;Cd();}else if(strcmp(enter_cmd,"echo")==0&&strcmp(gArgv[1],"$?")==0){yes=1;printf("%d\n",lastcode);lastcode=0;}return yes;
}
int main()
{int quit=0;while(!quit){//1.输出命令行MakeCommandLine();//2.获取输入命令char usercommand[SIZE];int n=  GetUserCommand(usercommand,sizeof(usercommand));if(n<=0) return 1;//3.命令行字符串分割SplitCommand(usercommand,sizeof(usercommand));  //4.检查是否为内建命令;n=CheckBuildin();if(n)continue;//执行命令ExecuteCommand();}return 0;}

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

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

相关文章

小程序高度问题背景scss

不同的机型&#xff0c;他的比例啥的都会不一样&#xff0c;同样的rpx也会有不同的效果。所以这里选择了取消高度。 <view class"box-border" :style"{padding-top: ${navHeight}px,}"><!-- 已登录 --><view v-if"userStore.userInfo&…

DeepSeek 15天指导手册——从入门到精通 PDF(附下载)

DeepSeek使用教程系列--DeepSeek 15天指导手册——从入门到精通pdf下载&#xff1a; https://pan.baidu.com/s/1PrIo0Xo0h5s6Plcc_smS8w?pwd1234 提取码: 1234 或 https://pan.quark.cn/s/2e8de75027d3 《DeepSeek 15天指导手册——从入门到精通》以系统化学习路径为核心&…

element-ui的组件使用

1. 安装 Element UI&#xff08;在文件夹最上面输入cmd进入dos窗口&#xff0c;然后输入安装指令 npm install element-ui --save&#xff09; 2.在main.js文件全局引入(main.js文件负责 全局注册 )&#xff0c;在该文件注册的所有组件在其他文件都能直接调用&#xff0c;一般…

List的模拟实现(2)

前言 上一节我们讲解了list的基本功能&#xff0c;那么本节我们就结合底层代码来分析list是怎么实现的&#xff0c;那么废话不多说&#xff0c;我们正式进入今天的学习&#xff1a;&#xff09; List的底层结构 我们先来看一下list的底层基本结构&#xff1a; 这里比较奇怪的…

RT-Thread+STM32L475VET6实现红外遥控实验

文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟&#xff0c;并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…

速通HTML

HTML基础 1.快捷键 基于VS Code记录编写过程中常用的快捷键 功能快捷键生成HTML基本骨架!回车保存代码CtrlS在浏览器运行代码AltB注释Ctrl/缩进Tab取消缩进ShiftTab收起侧边栏CtrlB 先保存&#xff0c;再在浏览器运行才能刷新 2.标签 标签作用h1——h6双标签标题标签&#…

WebXR教学 01 基础介绍

什么是WebXR&#xff1f; 定义 XR VR AR Web上使用XR技术的API WebXR 是一组用于在 Web 浏览器中实现虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;应用的技术标准。它由 W3C 的 Immersive Web 工作组开发&#xff0c;旨在提供跨设备的沉浸式体验…

IRI 2016 模型在线版 MATLAB

IRI官网&#xff1a;International Reference Ionosphere IRI-2016在线计算&#xff1a;IRI 2016 | CCMC 官方提供的MATLAB代码需要联网读取IRI网页数据&#xff1a; 下载需要注册账号&#xff0c;没有注册账号的自行注册&#xff0c;下载好后解压是这样的&#xff1a; 下载I…

数据结构系列一:初识集合框架+复杂度

前言 数据结构——是相互之间存在一种或多种特定关系的数据元素的集合。数据结构是计算机专业的基础课程&#xff0c;但也是一门不太容易学好的课&#xff0c;它当中有很多费脑子的东西&#xff0c;之后在学习时&#xff0c;你若碰到了困惑或不解的地方 都是很正常的反应&…

智慧物业平台(springboot小程序论文源码调试讲解)

第4章 系统设计 用户对着浏览器操作&#xff0c;肯定会出现某些不可预料的问题&#xff0c;但是不代表着系统对于用户在浏览器上的操作不进行处理&#xff0c;所以说&#xff0c;要提前考虑可能会出现的问题。 4.1 系统设计思想 系统设计&#xff0c;肯定要把设计的思想进行统…

2024年国赛高教杯数学建模A题板凳龙闹元宵解题全过程文档及程序

2024年国赛高教杯数学建模 A题 板凳龙闹元宵 原题再现 “板凳龙”&#xff0c;又称“盘龙”&#xff0c;是浙闽地区的传统地方民俗文化活动。人们将少则几十条&#xff0c;多则上百条的板凳首尾相连&#xff0c;形成蜿蜒曲折的板凳龙。盘龙时&#xff0c;龙头在前领头&#x…

在PyCharm中集成AI编程助手并嵌入本地部署的DeepSeek-R1模型:打造智能开发新体验

打造智能开发新体验&#xff1a;DeepSeekPycharmollamaCodeGPT 目录 打造智能开发新体验&#xff1a;DeepSeekPycharmollamaCodeGPT前言一、什么是ollama&#xff1f;二、如何使用1.进入ollama官方网站:2.点击下载ollama安装包3.根据默认选项进行安装4.安装成功5.打开命令提示符…

软件测试的基础入门(一)

文章目录 一、什么是软件测试&#xff1f;&#xff08;1&#xff09;生活中的测试案例&#xff08;2&#xff09;代码中的测试示例&#xff08;3&#xff09;软件测试的定义 二、软件测试的重要性三、测试工程师&#xff08;1&#xff09;定义&#xff08;2&#xff09;分类&am…

Linux版本控制器Git【Ubuntu系统】

文章目录 **前言**一、版本控制器二、Git 简史三、安装 Git四、 在 Gitee/Github 创建项目五、三板斧1、git add 命令2、git commit 命令3、git push 命令 六、其他1、git pull 命令2、git log 命令3、git reflog 命令4、git stash 命令 七、.ignore 文件1、为什么使用 .gitign…

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…

Spring Boot 3 整合 Spring Cloud Gateway 工程实践

引子 当前微服务架构已成为中大型系统的标配&#xff0c;但在享受拆分带来的敏捷性时&#xff0c;流量治理与安全管控的复杂度也呈指数级上升。因此&#xff0c;我们需要构建微服务网关来为系统“保驾护航”。本文将会通过一个项目&#xff08;核心模块包含 鉴权服务、文件服务…

flutter项目构建常见问题

最近在研究一个验证码转发的app&#xff0c;原理是尝试读取手机中对应应用的验证码进行自动转发。本次尝试用flutter开发&#xff0c;因为之前没有flutter开发的经验&#xff0c;遇到了诸多环境方面的问题&#xff0c;汇总一些常见的问题如下。希望帮助到入门的flutter开发者&a…

Classic Control Theory | 12 Real Poles or Zeros (第12课笔记-中文版)

笔记链接&#xff1a;https://m.tb.cn/h.Tt876SW?tkQaITejKxnFLhttps://m.tb.cn/h.Tt876SW?tkQaITejKxnFL

图解感知机(Perceptron)

目录 1.感知机&#xff08;Perceptron&#xff09;介绍 2.网络结构与工作原理 3.模型工作示例 4.总结 1.感知机&#xff08;Perceptron&#xff09;介绍 感知机&#xff08;Perceptron&#xff09;是最早的人工神经网络模型之一&#xff0c;由弗兰克罗森布拉特&#xff08;…

多旋翼+航模+直升机:多型号无人机飞行表演技术详解

多旋翼、航模、直升机等多种型号的无人机飞行表演技术&#xff0c;是现代科技与艺术的完美结合&#xff0c;它们通过精密的编程、高效的通信、先进的定位与导航技术&#xff0c;以及复杂的编队控制算法&#xff0c;共同呈现出令人震撼的视觉效果。以下是对这些无人机飞行表演技…