mybash---打造自己的命令解释器

目前我们Linux的系统默认的命令解释器是bash;
命令解释器(也称为命令行解释器或shell)是计算机操作系统中的一个重要组件,它负责接收用户输入的命令,并解释和执行这些命令。其实命令解释器就是解析命令,执行命令,输出反馈;

1.命令的分类

内置命令和普通命令
1.内置命令:cd exit 2普通命令:ls pwd cp ps   等等
如果是普通命令,那么使用which是可以找到的,比如which ps;which ls;which pwd;which cp;
也就是普通命令是一个可执行程序.
但是我们找cd和exit是找不到的;  因为内置命令cd,exit等它是在bash本身实现的; 而bash也是一个可执行程序,比如:which bash;
简单来讲,就是普通命令是通过fork+exec实现的;而内置命令是bash自身通过调用相应的接口实现的;

2.项目框架

企业微信截图_16537102881089.png


3.strtok的介绍

字符串分割函数

image-20230928220131547.png

注意:

strtok线程不安全,原因就是函数实现使用了一个static的变量(指针记录下次分割的地址,再次调用要沿用上次的,所以需要静态变量).
在多线程中,如果两个线程都使用了strtok的话,这个变量的值就会被另一个线程不定期的进行修改.

4.mybash.c

#include<assert.h>
#include<wait.h>
#include<sys/types.h>
#include<pwd.h>
#include<sys/utsname.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define ARG_MAX 10
#define CHAR_MAX 128
char* get_cmd(char* buff,char* myargv[])
{if(buff==NULL||myargv==NULL){perror("buff为NULL或myargv为NULL\n");return NULL;}char* s=strtok(buff," ");int i=0;while(s!=NULL){myargv[i++]=s;s=strtok(NULL," ");}return myargv[0];
}
char* getpath()
{char buf[CHAR_MAX];//当前的绝对路径getcwd(buf,CHAR_MAX);char* stdpath=(char*)malloc(CHAR_MAX);//用户家目录uid_t uid=getuid();struct passwd* pw;pw=getpwuid(uid);strcpy(stdpath,pw->pw_dir);int i=0;char* path=(char*)malloc(CHAR_MAX);while(stdpath[i]!='\0'){if(buf[i]!=stdpath[i]){strcpy(path,buf);break;}i++;}if(stdpath[i]=='\0'){strcpy(path,"~");if(strchr(strstr(buf,getlogin()),'/')!=NULL){strcat(path,strchr(strstr(buf,getlogin()),'/'));}}return path;
}
int main(int argc,char* argv[])
{char* myenvp[]={"/home/stu/bash/mybin"};//获取主机名struct utsname uts;uname(&uts);/*char* hostname[128]={0};* if(gethostname(hostname,128)==-1)* {*      printf("mybash1.0>>>  ");*      fflush(stdout);* }*///获取用户iduid_t uid=getuid();char user='$';if(uid==0){user='#';}while(1){printf("\033[1;35m%s@%s\033[0m:\033[1;34m%s\033[0m%c ",getlogin(),uts.nodename/*hostname*/,getpath(),user);//命令提示符fflush(stdout);//刷新缓冲区char buff[CHAR_MAX];fgets(buff,CHAR_MAX,stdin);//从键盘获取命令buff[strlen(buff)-1]='\0';//解析命令char* myargv[ARG_MAX]={0};char* cmd=get_cmd(buff,myargv);//命令//如果是内置命令if(cmd==NULL){continue;}else if(strcmp(cmd,"cd")==0){if(myargv[1]!=NULL){if(chdir(myargv[1])==-1){perror("path error\n");}}else{char path[128]="/home/";strcat(path,getlogin());chdir(path);}      }else if(strcmp(cmd,"exit")==0){break;}//如果是普通命令else{pid_t pid=fork();assert(pid!=-1);if(pid==0){char pathname[CHAR_MAX]={0};strcat(strcpy(pathname,"/home/stu/bash/mybin/"),cmd);execv(pathname,myargv);perror("execve error!\n");exit(0);}else{wait(NULL);}}}exit(0);
}

5.拓展

上面的代码我们实现了通过fork+exec的模式,子进程调用了系统的对应命令的可执行文件,并没有完全自己实现命令,而要实现这个功能呢,就需要你将每一个命令都实现出来,这是一个硕大的工程,但也不要灰心,我们可以实现先一些简单的命令练练手,也算是自己实现过了。

这里给大家放一个ls命令的实现

#include <stdio.h>struct dirent *s=NULL;while((s=readdir(pdir))!=NULL){   if(strncmp(s->d_name,".",1)==0){continue;}//printf("%s   ",s->d_name);struct stat filestat;stat(s->d_name,&filestat);if(S_ISDIR(filestat.st_mode)){printf("\033[1;34m%s\033[0m  ",s->d_name);}else{if(filestat.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)){printf("\033[1;32m%s\033[0m  ",s->d_name);}else{printf("%s  ",s->d_name);}}}   printf("\n");closedir(pdir);exit(0);
}

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

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

相关文章

linux 云计算平台基本环境(知识准备篇)

为了更多的了解云计算平台&#xff0c;结合云计算和linux的知识写了一篇云计算的介绍和汇总。 文章目录 前言1. centos的软件管理1.1 yum软件包管理1.1.1 yum命令语法&#xff1a;1.1.2 安装软件包的步骤1.1.3 yum源 2. 主机名管理与域名解析3. centos的防火墙管理4. openstack…

docker-compose yaml指定具体容器网桥ip网段subnet;docker创建即指定subnet;docker取消自启动

1、docker-compose yaml指定具体容器网桥ip网段subnet docker-compose 启动yaml有时可能的容器网段与宿主机的ip冲突导致宿主机上不了网&#xff0c;这时候可以更改yaml指定subnet 宿主机内网一般是192**&#xff0c;这时候容器可以指定172* version: 3.9 services:coredns:…

CentOS如何使用Docker部署Plik服务并实现公网访问本地设备上传下载文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

IP代理池:隐私保护的得力助手与强化策略

目录 前言 1. IP代理池的原理 2. IP代理池的实现 3. 强化策略 总结 代码示例&#xff08;Python&#xff09; 前言 随着互联网的快速发展&#xff0c;越来越多的网络应用和服务涌现出来&#xff0c;我们的个人隐私也面临着越来越大的威胁。在这个数字化时代&#xff0c;…

Xxl-job执行器自动注册不上的问题

今天新建的项目要部署xxl-job&#xff0c;之前部署过好多次&#xff0c;最近没怎么部署&#xff0c;生疏了。部署完之后&#xff0c;服务一直没有注册到执行器管理里面&#xff0c;找了半天也没找到原因&#xff0c;看数据库里的xxl_job_registry表也是一直有数据进来。 后来看…

如何在Linux通过docker搭建Plik文件系统并实现无公网IP管理内网文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

标准版uni-app移动端页面添加/开发操作流程

页面简介 uni-app项目中&#xff0c;一个页面就是一个符合Vue SFC规范的.vue文件或.nvue文件。 .vue页面和.nvue页面&#xff0c;均全平台支持&#xff0c;差异在于当uni-app发行到App平台时&#xff0c;.vue文件会使用webview进行渲染&#xff0c;.nvue会使用原生进行渲染。…

结合文本的目标检测:Open-GroundingDino训练自己的数据集

1、简单介绍 Open-GroundingDino是GroundingDino的第三方实现训练流程的代码&#xff0c;因为官方GroundingDino没有提供训练代码&#xff0c;只提供了demo推理代码。 关于GroundingDino的介绍可以看论文&#xff1a;https://arxiv.org/pdf/2303.05499.pdf GroundingDino的G…

盒子模型+响应式布局 + 原型链与继承

盒子模型 是什么 css布局基础,规定了元素在页面上如何呈现,以及元素之间的空间关系 由content paddingbordermargin四部分组成 为什么 盒子模型分为 标准盒子模型: 元素的宽度与高度 只包括content IE盒子模型: 元素的宽度与高度 包括content,padding,border 在实际操作中…

浮点数在内存中的存储

索引 1. 浮点数在内存中的存储2. 浮点数存的过程3. 浮点数取的过程4. 题目解析 正文开始 1. 浮点数在内存中的存储 常见的浮点数: 3.14159 , 1E10等, 浮点数家族包括 : float , double , long double类型. 浮点数的表示范围在 float.h中定义. (1E10为科学计数法表示1.0 * 2的…

openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装

文章目录 openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装263.1 安装jdk263.2 安装numactl263.3 安装ant263.4 安装htop工具 openGauss学习笔记-263 openGauss性能调优-TPCC性能调优测试指导-前置软件安装 本章节主要介绍openGauss数据库内核基于…

冯喜运:4.15汇市观潮:现货黄金美原油技术分析

【 黄金消息面分析】&#xff1a;周一(4月15日)亚市盘初&#xff0c;金价开盘跳涨13美元&#xff0c;报2357.71美元/盎司&#xff0c;随后延续涨势&#xff0c;最高触及2372.45美元/盎司&#xff0c;目前金价回落至2354.19美元/盎司&#xff0c;如果中东局势未进一步恶化&#…