【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;

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

R与RStudio简介及安装

目录 一、R与RStudio关系 二、R简介 2.1. 发展历史 2.2. R语言特点 三、安装指南 3.1 R安装指南 3.2 R studio安装指南 一、R与RStudio关系 R是统计领域广泛使用的工具&#xff0c;属于GNU系统的一个自由、免费、源代码开放的软件&#xff0c;是 用于统计计算和统计绘图…

在MPSOC上运行ADRV9371射频子板

本例程实现在MPSOC开发板上运行ADRV9026的HDL官方提供的历程。 解压提供文件压缩包“adrv9026.zip”&#xff0c;解压后有三个文件夹&#xff0c;首先是“hdl-2023_R2”为vivado端的项目&#xff0c;里面有各种射频子板加不同底板的项目&#xff0c;本例程使用的是ZCU102…

全面理解-深拷贝与浅拷贝

在 C 中&#xff0c;深拷贝&#xff08;Deep Copy&#xff09; 和 浅拷贝&#xff08;Shallow Copy&#xff09; 是两种完全不同的对象拷贝策略&#xff0c;主要区别在于对指针和动态分配资源的处理方式。正确理解二者的区别是避免内存泄漏、悬空指针和程序崩溃的关键。 一、核…

STM32-智能小车项目

项目框图 ST-link接线 实物图&#xff1a; 正面&#xff1a; 反面&#xff1a; 相关内容 使用L9110S电机模块 电机驱动模块L9110S详解 | 良许嵌入式 一、让小车动起来 新建文件夹智能小车项目 在里面复制19-串口打印功能 重命名为01-让小车动起来 新建文件夹motor&…

计算机毕业设计SpringBoot+Vue.js古典舞在线交流平台(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

力扣2382. 删除操作后的最大子段和

力扣2382. 删除操作后的最大子段和 题目 题目解析及思路 题目要求找到每次删除一个元素的最大字段和 因为删除不好做&#xff0c;可以转删除为添加&#xff0c;用并查集维护当前子段和 两部分合并(两个并查集)&#xff0c;三部分求和(两个并查集和一个元素) 代码 class S…

PythonWeb开发框架—Django之DRF框架的使用详解

1.安装依赖包 pip install djangorestframework 2.配置应用 在settings.py中的INSTALLED_APPS中添加rest_framework应用 3.创建序列化器 序列化器是用来操作models的 第一步&#xff1a;定义models ##models.pyfrom django.db import models# Create your models here.cl…

链表(LinkedList)面试题

1.1 ​​​​​​203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 分析&#xff1a;题目的要求是移除链表中值为val的所有元素&#xff0c;因此这道题需要使用循环解决问题&#xff0c;删除过程需要记录前一个结点的信息&#xff0c;所以需要使用双坐标解决问题。 …

Windows golang安装和环境配置

【1】、golang 1.19 sdk下载 https://download.csdn.net/download/notfindjob/90422529 【2】、安装 【3】、配置 GOPATH目录 【4】、LiteIDE下载安装 https://download.csdn.net/download/notfindjob/90422580 【5】、打开LiteIDE&#xff0c;选择查看->管理GOPATH&…

3D Web轻量化引擎HOOPS Communicator如何赋能航空航天制造?

在当今航空航天制造领域&#xff0c;精确度、效率和协作是推动行业发展的关键要素。随着数字化技术的飞速发展&#xff0c;3D Web可视化开发包HOOPS Communicator 为航空航天制造带来了革命性的变化。它凭借强大的功能和灵活的应用&#xff0c;助力企业在设计、生产、培训等各个…

Starlink卫星动力学系统仿真建模第十讲-基于SMC和四元数的卫星姿态控制示例及Python实现

基于四元数与滑模控制的卫星姿态控制 一、基本原理 1. 四元数姿态表示 四元数运动学方程&#xff1a; 3. 滑模控制设计 二、代码实现&#xff08;Python&#xff09; 1. 四元数运算工具 import numpy as npdef quat_mult(q1, q2):"""四元数乘法""…

linux 命令+相关配置记录(持续更新...)

linux 命令记录相关配置记录 磁盘切换 cd D&#xff1a;#这里表示切换到D盘查看wsl 安装的linux 子系统 wsl --list -vwsl 卸载 linux 子系统 wsl --unregister -xxx # xxx 表示子系统的名字备份Linux 子系统 导出 wsl --export xxx yyy # xxx 表示子系统的名字 yyy 表示压…

山东大学软件学院nosql实验一环境配置

环境&#xff1a;前端vue后端springboot 软件环境&#xff1a; MongoDB MongoDBCompass 实验步骤与内容&#xff1a; 在官网下载安装包&#xff08;最新版&#xff09; 配置环境环境变量 在“高级系统设置-环境变量”中&#xff0c;可以将MongoDB添加到环境变量Path中(D:\…

云手机如何进行经纬度修改

云手机如何进行经纬度修改 云手机修改经纬度的方法因不同服务商和操作方式有所差异&#xff0c;以下是综合多个来源的常用方法及注意事项&#xff1a; 通过ADB命令注入GPS数据&#xff08;适用于技术用户&#xff09; 1.连接云手机 使用ADB工具连接云手机服务器&#xff0c;…

Deepseek本地化部署指南:在Linux环境下部署,windows远程web-ui访问(Ubuntu环境+window环境)

一、在Ubuntu服务器上部署DeepSeek模型 要在Ubuntu上通过Ollama安装和使用DeepSeek模型&#xff0c;可以按照以下步骤操作&#xff1a; 安装Ollama 1、使用命令安装Ollama 命令语句&#xff1a;curl -sSfL https://ollama.com/install.sh | sh 2、验证安装是否成功 安装完…

数据库(MySQL)二

MySQL 六、MySQL索引视图6.1 索引底层原理6.1.1 索引hash算法6.1.2 索引二叉树算法6.1.3 索引平衡二叉树算法6.1.4 索引BTREE树算法6.1.5 普通SQL全表扫描过程 6.2 索引分类6.2.1 按数据结构层次分类6.2.2 按字段数量层次分类6.2.3 按功能逻辑层次分类&#xff08;面试题&#…

element ui的select选择框

我们首先先试一下&#xff0c;这个东西怎么玩的 <el-select v-model"select" change"changeSelect"><el-option value"香蕉"></el-option><el-option value"菠萝"></el-option><el-option value&quo…

git 的一些操作总结

1. Git 分支及基础操作指令 1.1 创建分支 # 创建新分支 git branch <branch_name># 创建并切换到新分支 git checkout -b <branch_name>1.2 切换分支 # 切换到指定分支 git checkout <branch_name># 切换到上一个分支 git checkout -1.3 查看分支 # 查看…

华为2025年技术发布会:智能汽车核心技术大爆发

近日&#xff0c;华为在鸿蒙智行尊界技术发布会上发布了多项智能汽车核心技术&#xff0c;涵盖智能驾驶、安全防护、通信系统、座舱交互及电池技术等领域&#xff0c;标志着其从“被动智能”向“自主智能”的战略升级。 以下是核心技术的综合梳理&#xff1a; 六大核心创新 途…