【Linux】自己实现一个bash进程

news2024/11/26 6:54:27

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 1024
   10 #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])//特别处理ll
   35   {
   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       else
   86       {
   87         char* tmp=getenv(argv[1]+1);                                                                                                                   
   88         if(tmp)printf("%s\n",tmp);
   89       }
   90     }
   91     else
   92     {
   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 }

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

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

相关文章

如何解决链游中可能出现的延迟或网络拥堵问题?

随着区块链技术的不断发展和普及&#xff0c;链游&#xff08;基于区块链的游戏&#xff09;作为新兴的娱乐形式&#xff0c;正逐渐走进大众的视野。然而&#xff0c;与传统游戏相比&#xff0c;链游在运行过程中可能会遇到一些特有的问题&#xff0c;其中最为突出的就是延迟和…

Windows hook介绍与代码演示

Windows Hook 是一种机制&#xff0c;允许应用程序监视系统或处理特定事件。它可以拦截和更改消息&#xff0c;甚至可以插入到其他应用程序的消息处理机制中。Windows 提供了多种挂钩类型&#xff0c;例如键盘挂钩、鼠标挂钩、消息挂钩等。 hook代码实现 下面是一个使用 Wind…

微服务架构下的‘黑带’安全大师:Spring Cloud Security全攻略!

深入探讨了微服务间的安全通信、安全策略设计以及面对经典安全问题的应对策略。无论你是微服务的新手还是资深开发者&#xff0c;都能在本文中找到提升安全功力的秘籍。让我们一起成为微服务架构下的‘黑带’安全大师&#xff01; 文章目录 1. 引言微服务安全挑战与重要性Sprin…

【软件工程】【23.04】p1

关键字&#xff1a; 软件模型、提炼、加工表达工具、通信内聚、访问依赖、边界类交互分析、RUP核心工作流、首先测试数据流、软件验证过程、CMMI过程域分类工程类&#xff1b; 软件工程目的、功能需求是需求的主体、结构化方法、耦合、详细设计工具、类、类图、RUP采用用例技…

rk3568_mutex

文章目录 前言1、什么是mutex?1.1mutex互斥体API函数二、实验2.1实验目的2.2源码2.3结果图前言 本文记录的是rk3568开发板基础上做的mutex实验 1、什么是mutex? mutex是互斥体,它是比信号量semaphore更加专业的机制。 在我们编写Linux驱动的时候遇到需要互斥的地方建议使用…

Nginx企业级负载均衡:技术详解系列(12)—— 深入解析root、alias及location

你好&#xff0c;我是赵兴晨&#xff0c;97年文科程序员。 在生产服务器的Nginx配置中&#xff0c;我们总会遇到形形色色的配置方案。你是否曾注意到root和alias指令的巧妙应用&#xff1f;是否对那些五花八门的location匹配规则感到好奇&#xff1f; 今天&#xff0c;咱们来聊…

微服务架构-分支微服务设计模式

微服务架构-分支微服务设计模式 这种模式是聚合器模式的扩展&#xff0c;允许同时调用两个微服务链 分支微服务设计模式是一种用于构建大型系统的微服务架构模式&#xff0c;其核心思想是 将复杂的业务逻辑拆解为多个小的、相互独立的子系统&#xff0c;每个子系统由一个或多…

家政项目day2 需求分析(模拟入职后熟悉业务流程)

目录 1 项目主体介绍1.1 项目背景1.2 运营模式1.3 项目业务流程 2 运营端需求2.1 服务类型管理2.2 服务项目&#xff08;服务&#xff09;管理2.3 区域管理2.4 区域服务管理2.5 相关数据库表的管理2.6 设计工程结构2.7 测试接口&#xff08;接口断点查看业务代码&#xff09; 1…

SQL学习小记(三)

SQL学习小记&#xff08;三&#xff09; 功能实现思路代码部分名词解释 代码打包为可执行文件 功能说明&#xff1a;使用python代码&#xff0c;将数据库database1中的表格table1同步到数据库database2中 功能实现 思路 #mermaid-svg-R1pWrEWA799M299a {font-family:"tre…

Redis 中 List 数据结构详解

目录 List 用法 1. 增 2. 删 3. 查 内部编码 应用场景 前言 Redis 中的 List 和 Set 数据结构各有特点&#xff0c;适用于不同的应用场景。List 提供了有序的列表结构&#xff0c;适合用于消息队列和任务列表等场景&#xff1b;Set 提供了无序且不重复的集合结构&#…

【全开源】旅游系统源码(Uniapp+FastAdmin+ThinkPHP)

一款基于UniappFastAdminThinkPHP开发的旅游系统&#xff0c;包含消费者端&#xff08;手机端&#xff09;、机构工作人员&#xff08;手机端&#xff09;、机构端&#xff08;PC&#xff09;、平台管理端&#xff08;PC&#xff09;。机构可以发布旅游线路、景点项目&#xff…

Wpf 使用 Prism 实战开发Day27

首页汇总和数据动态显示 一.创建首页数据汇总数据接口 汇总&#xff1a;待办事项的总数已完成&#xff1a;待办事项里面有多少条完成的待办完成比例&#xff1a;已完成和汇总之间的比例备忘录&#xff1a;显示备忘录的总数待办事项&#xff1a;显示待办事项未完成的集合备忘录&…

Java实现对PDF、纵向、横向页面添加自定义水印功能

Java实现对PDF、纵向、横向页面添加自定义水印 效果图 -- 纵向 页面PDF使用到JAR Maven依赖版本效果图 -- 横向页面PDF 效果图 – 纵向 页面PDF 代码如下&#xff1a; 使用到JAR Maven依赖版本 <dependency><groupId>org.apache.pdfbox</groupId><artifa…

视频监控平台AS-V1000 的场景管理,一键查看多画面视频的场景配置、调用、管理(一键浏览多路视频)

目录 一、场景管理的定义 二、场景管理的功能和特点 1、功能 &#xff08;1&#xff09;场景配置 &#xff08;2&#xff09;实时监控 &#xff08;3&#xff09;权限管理 2、特点 三、AS-V1000的场景配置和调用 1、场景配置 &#xff08;1&#xff09;实时视频预览 …

【Linux】Linux的权限_2 + Linux环境基础开发工具_1

文章目录 三、权限3. Linux权限管理修改文件的拥有者和所属组 4. 文件的类型5. 权限掩码 四、Linux环境基础开发工具1. yumyum 工具的使用 未完待续 三、权限 3. Linux权限管理 修改文件的拥有者和所属组 在上一节我们讲到如何更改文件的访问权限&#xff0c;那我们需要更改…

在VS Code中进行Java的单元测试

在VS Code中可以使用 Test Runner for Java扩展进行Java的测试执行和调试。 Test Runner for Java的功能 Test Runner for Java 结合 Language Support for Java by Red Hat 和 Debugger for Java这两个插件提供如下功能&#xff1a; 运行测试&#xff1a; Test Runner for …

算法打卡 Day13(栈与队列)-滑动窗口最大值 + 前 K 个高频元素 + 总结

文章目录 Leetcode 239-滑动窗口最大值题目描述解题思路 Leetcode 347-前 K 个高频元素题目描述解题思路 栈与队列总结 Leetcode 239-滑动窗口最大值 题目描述 https://leetcode.cn/problems/sliding-window-maximum/description/ 解题思路 在本题中我们使用自定义的单调队列…

②单细胞学习-组间及样本细胞比例分析

目录 数据读入 每个样本各细胞比例 两个组间细胞比例 亚组间细胞比例差异分析&#xff08;循环&#xff09; 单个细胞类型亚新间比例差异 ①单细胞学习-数据读取、降维和分群-CSDN博客 比较各个样本间的各类细胞比例或者亚组之间的细胞比例差异 ①数据读入 #各样本细胞…

ios 端如何免费使用Emby???(利用Quantumult X )

本文转自博主的个人博客&#xff1a;https://blog.zhumengmeng.work,欢迎大家前往查看。 原文链接&#xff1a;点我访问 注意&#xff1a;使用此激活方式&#xff0c;有唯一缺点&#xff0c;在观看Emby时需保持Quantumult X为开启状态&#xff01; 一、安装证书 开启 MitM 后…

android11禁止进入屏保和自动休眠

应某些客户要求&#xff0c;关闭了开机进入屏保&#xff0c;一段时间会休眠的问题。以下diff可供参考&#xff1a; diff --git a/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/overlay/frameworks/base/packages/SettingsProvider/res/value…