【Linux】自主shell编写

news2024/10/8 10:54:46

如果学习了常见的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 sucess
             lastcode = 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 512
 13 #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.coloradmin.cn/o/2196171.html

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

相关文章

定制化的新生代 Layer1 代币经济学

原文标题&#xff1a;《Next-Gen Layer 1 Tokenomics: Three Pillars for the Token Flywheel》 撰文&#xff1a;Eren&#xff0c;Four Pillars 编译&#xff1a;Tia&#xff0c;Techub News Layer1 代币经济学的转变 最近获得大量关注和大量投资的项目&#xff08;如 Berac…

避免误修改:如何在Word中锁定指定内容?

在工作中&#xff0c;保护Word文档的某些部分免于被他人修改是一项常见需求。无论是分享给同事、客户&#xff0c;还是用作正式的合同文件&#xff0c;都需要确保关键内容不被随意更改。今天我们一起来看看&#xff0c;如何在Word文档中锁定部分内容&#xff0c;使其无法编辑修…

数据结构--线性表双向链表的实现

目录 思路设计 总体思维导图 插入部分 头插法尾插法 任意位置插入 删除部分 头结点 尾节点 中间节点 只有头结点且删除的就是头结点 ​编辑 清空链表部分 遍历清空链表的所有节点 不遍历清空 各部分代码 Main部分 MyListedList部分 IndexOutOfException部分 …

微软发布Windows 11 2024更新,新型Copilot+ AI PC功能亮相

前言 微软在Windows 11的2024更新中加强了对人工智能的应用&#xff0c;推出了新功能Copilot。 此次更新的版本号为26100.1742&#xff0c;Copilot将首先在Windows Insider中推出&#xff0c;计划于11月向特定设备和市场推广&#xff0c;用户需开启“尽快获取最新更新”选项以…

Eureka的搭建、注册和拉取

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

敢为天下先:论特斯拉轿车设计理念和六西格玛设计方法的应用-张驰咨询

全球竞争日益激烈的电动汽车市场&#xff0c;特斯拉通过其独特的设计理念和创新能力脱颖而出。其核心驱动因素之一&#xff0c;是特斯拉在设计和制造中的第一性原理**&#xff08;First Principles&#xff09;思维&#xff0c;以及通过应用六西格玛设计方法实现的高质量制造流…

YoloV10改进策略:BackBone改进|CAFormer在YoloV10中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入YoloV10模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

51c自动驾驶~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/11491137 #BEVWorld BEV潜在空间构建多模态世界模型&#xff0c;全面理解自动驾驶~一、引言 世界模型建模了有关环境的知识&#xff0c;其可以通过给定的条件对未来进行合理的想象。未来想象要求世界模型具有物理规律的理解…

五万字综述!Prompt Tuning:深度解读一种新的微调范式

导读 本文将深入解读Prompt-Tuning的微调范式&#xff0c;以综述讨论的形式展开。 \ 这绝对是我看过最全面细致的Prompt Tuning技术综述之一&#xff0c;全文共五万多字&#xff0c;看完之后你一定发出一样的感叹&#xff01; 阅读该博客&#xff0c;您将系统地掌握如下知识…

【操作系统】虚拟机

&#x1f339;&#x1f60a;&#x1f339;博客主页&#xff1a;【Hello_shuoCSDN博客】 ✨操作系统详见 【操作系统专项】 ✨C语言知识详见&#xff1a;【C语言专项】 首先先来了解传统的计算机 在生产的时候&#xff0c;物理机器&#xff08;硬件&#xff09;其实是非常强大的…

32 基于51单片机的电机控制和角度检测

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用滑动变阻器连接ADC0832数模转换器模拟角度传感器&#xff0c;然后通过LCD1602显示数值&#xff0c;然后按键按下不动&#xff0c;电机正转&#xff0c;松开停止。第二…

DHCP Snooping典型配置举例(如何防止路由器乱接问题)

全局开启DHCP Snooping配置举例 组网需求 Router B通过以太网端口Ten-GigabitEthernet0/0/6连接到合法DHCP服务器&#xff0c;通过以太网端口Ten-GigabitEthernet0/0/8连接到非法DHCP服务器&#xff0c;通过Ten-GigabitEthernet0/0/7连接到DHCP客户端。要求&#xff1a; 与合…

33 基于单片机的智能窗帘控制系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用DHT11温湿度传感器检测温湿度&#xff0c;滑动变阻器连接ADC0832数模转换器转换模拟,光敏传感器&#xff0c;采用GP2D12红外传感器&#xff0c;通过LCD1602显示屏显示…

嵌入式硬件设计知识详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

015 品牌关联分类

文章目录 后端CategoryBrandEntity.javaCategoryBrandController.javaCategoryBrandServiceImpl.javaCategoryServiceImpl.javaBrandServiceImpl.java删除 npm install pubsub-jsnpm install --save pubsub-js这个错误是由于在尝试安装 pubsub-js 时&#xff0c;npm 发现了项目…

Python 如何使用 multiprocessing 模块创建进程池

Python 如何使用 multiprocessing 模块创建进程池 一、简介 在现代计算中&#xff0c;提升程序性能的一个关键方法是并行处理&#xff0c;尤其是当处理大量数据或计算密集型任务时&#xff0c;单线程可能不够高效。Python 提供了多个模块来支持并行计算&#xff0c;其中最常用…

爬虫案例——爬取长沙房产网租房信息

需求&#xff1a; 1.爬取长沙房产网租房信息&#xff08;长沙租房信息_长沙出租房源|房屋出租价格【长沙贝壳租房】 包括租房标题、标题链接&#xff0c;价格和地址 2.实现翻页爬取 3.使用bs4解析数据 分析 1.抓取正确的数据包——看响应内容 找到正确的后&#xff0c;复…

大模型之RAG-关键字检索的认识与实战(混合检索进阶储备)

前言 按照我们之前的分享&#xff08;大模型应用RAG系列3-1从0搭建一个RAG&#xff1a;做好文档切分&#xff09;&#xff1a; RAG系统搭建的基本流程 准备对应的垂域资料文档的读取解析&#xff0c;进行文档切分将分割好的文本灌入检索引擎&#xff08;向量数据库&#xff…

如何使用ssm实现新冠病毒校园监控平台的设计与实现+vue

TOC ssm812新冠病毒校园监控平台的设计与实现vue 绪论 课题背景 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化。目前&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得…

python画图|曲线动态输出基础教程

在前述学习过程中&#xff0c;已经掌握基本的曲线图像画法&#xff0c;并尝试探索过3D动画基础教程。 相关文章可以通过下述链接直达&#xff1a; python画三角函数图|小白入门级教程_正余弦函数画图python-CSDN博客 python动画教程|Animations using Matplotlib-官网教程程…