【Linux】Shell命令行的简易实现(C语言实现)内键命令,普通命令
文章目录
- 0.准备工作
- 1.大体框架
- 一、获取命令行
- 二、解析命令行
- 三、进程执行
- 1.普通命令
- 2.内建命令
- 四、完整代码:
0.准备工作

1.大体框架
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
//用于修饰命令行
//类似:[hh@VM-4-10-centos ~]$ #define LINE_SIZE 1024//输入命令最大长度
#define ARGC_SIZE 32//命令行参数表的大小
#define EXIT_CODE 44//退出码int lastcode = 0;//上一次的退出码
int quit = 0char commandline[LINE_SIZE];//输入的命令
char *argv[ARGC_SIZE];//解析后保存的命令
char pwd[LINE_SIZE];//保存当前所在路径// 自定义环境变量表
char myenv[LINE_SIZE];//因为环境变量表里面保存的不是//变量本身,而是其地址,所以我们为了防止//自己导入的环境变量被覆盖,需要自己维护一段空间//这里myenv只能维护一个环境变量,因为只有一个地址const char *getusername()
{//获取用户名return getenv("USER");
}const char *gethostname()
{//获取主机名return getenv("HOSTNAME");
}void getpwd()
{
//将当前路径保存到pwd中getcwd(pwd, sizeof(pwd));
}void interact(char *cline, int size){ }//获取命令行int splitstring(char cline[], char *_argv[]){}//解析命令行void NormalExcute(char *_argv[]){}//执行普通命令int buildCommand(char *_argv[], int _argc){}//执行内键命令int main()
{while(!quit){// 1.// 2. 交互问题,获取命令行 interact(commandline, sizeof(commandline));// 3. 子串分割的问题,解析命令行int argc = splitstring(commandline, argv);if(argc == 0) continue;// 4. 指令的判断 //内键命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);// 5. 普通命令的执行if(!n) NormalExcute(argv);}return 0;
}
一、获取命令行
在获取命令之前我们需要先建立一个命令行
类似这种效果:
void interact(char *cline, int size)
{getpwd();//将当前路径写入到pwd中printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname(), pwd);fgets(cline, size, stdin);//这里不用scanf的原因是其遇到空格与回车不会读取//所以我们选择用fgets,将命令写入cline中// "abcd\n\0"//又因为fgets会读入回车键,所以我们要手动把回车位置改为'\0'cline[strlen(cline)-1] = '\0';
}
二、解析命令行
int splitstring(char cline[], char *_argv[])
{int i = 0;//strtok用于分割字符串,上面我们宏定义了只有要DELIM中的字符//就会发生分割,将分割后的字符串写入argv中argv[i++] = strtok(cline, DELIM);while(_argv[i++] = strtok(NULL, DELIM)); // 故意写的=return i - 1;//返回argv中存的字符串个数
}
三、进程执行
1.普通命令
void NormalExcute(char *_argv[])
{pid_t id = fork();//创建子进程if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令//execvp相当于一个加载器//该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行//会从环境变量中的路径中找到我们的可执行程序execvp(_argv[0], _argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {//等待子进程成功,更改退出码lastcode = WEXITSTATUS(status);}}
}
2.内建命令

int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){//chdir改变当前进程路径//假如我们让子进程执行cd命令,子进程确实路径改变了//但子进程执行完就被父进程回收了,没屁用//因为进程的独立性我父进程路径不受影响。//所以我们要手动修改路径chdir(argv[1]);getpwd();//将新的路径写入pwd//改变环境变量PWD,用pwd对其进行写入sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){//自己维护环境变量空间strcpy(myenv, _argv[1]);//将环境变量放入自己的myenvputenv(myenv);return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1], "$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){//_argv[1]+1为$后面的值例如$PATH//那么最后就获取PATH的值char *val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}else{printf("%s\n", _argv[1]);}return 1;}// 特殊处理一下ls//因为ls中如果是可执行文件,其会显示为特殊颜色if(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}
四、完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];// 自定义环境变量表
char myenv[LINE_SIZE];const char *getusername()
{return getenv("USER");
}const char *gethostname()
{return getenv("HOSTNAME");
}void getpwd()
{getcwd(pwd, sizeof(pwd));
}void interact(char *cline, int size)
{getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(), gethostname(), pwd);fgets(cline, size, stdin);// "abcd\n\0"cline[strlen(cline)-1] = '\0';
}int splitstring(char cline[], char *_argv[])
{int i = 0;argv[i++] = strtok(cline, DELIM);while(_argv[i++] = strtok(NULL, DELIM)); return i - 1;
}void NormalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令//execvpe(_argv[0], _argv, environ);execvp(_argv[0], _argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id) {lastcode = WEXITSTATUS(status);}}
}int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){chdir(argv[1]);getpwd();sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1], "$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){char *val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}else{printf("%s\n", _argv[1]);}return 1;}// 特殊处理一下lsif(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}int main()
{while(!quit){// 1.// 2. 交互问题,获取命令行 interact(commandline, sizeof(commandline));// 3. 子串分割的问题,解析命令行int argc = splitstring(commandline, argv);if(argc == 0) continue;// 4. 指令的判断 //内键命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);// 5. 普通命令的执行if(!n) NormalExcute(argv);}return 0;
}
相关文章:
【Linux】Shell命令行的简易实现(C语言实现)内键命令,普通命令
文章目录 0.准备工作1.大体框架 一、获取命令行二、解析命令行三、进程执行1.普通命令2.内建命令 四、完整代码: 0.准备工作 1.大体框架 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <u…...
Kafka -- 架构、分区、副本
1、Kafka的架构: 1、producer:消息的生产者 2、consumer:消息的消费者 3、broker:kafka集群的服务者,一个broker就是一个节点,主要是负责处理消息的读、写的请求和存储消息。在kafka cluster中包含很多的br…...
CSS特效001:鼠标放div上,实现旋转、放大、移动等效果
GPT能够很好的应用到我们的代码开发中,能够提高开发速度。你可以利用其代码,做出一定的更改,然后实现效能。 css实战中,经常会看到这样的场景,鼠标放到一个图片或者一个div块状时候,会出现旋转、放大、移动…...
gin 快速入门手册
文章目录 安装URL和路由分组2. 带参数的url3. 获取路由分组的参数 获取参数1. 获取get参数2. 获取post参数3. get、post混合 JSON 、 ProtoBuf渲染1. 输出json和protobuf2. PureJSON 表单验证1. 表单的基本验证 中间件和next函数1. 无中间件启动2. 使用中间件3. 自定义组件 设置…...
Window下安装 Mongodb,并实现单点事务
在window操作系统下安装Mongodb,并让单点mongodb支持事务,mongodb5以上时才支持事务,所以必须时mongodb5及以上版本才支持。 1、下载mongodb安装文件 (1) 下载mongodb msi 安装文件 地址:mongocommunity &…...
【通信原理】第三章 随机过程——例题
一、随机过程 1. 数学特征 ① 随机信号(三角函数表达式) ② 随机信号(求和表达式) 2. 功率谱密度 ① 相位确定,求功率谱密度 ② 已知相位分布,求功率谱密度 ③ 信号为两信号之和,求功率谱密度…...
线性【SVM】数学原理和算法实现
一. 数学原理 SVM是一类有监督的分类算法,它的大致思想是:假设样本空间上有两类点,如下图所示,我们希望找到一个划分超平面,将这两类样本分开,我们希望这个间隔能够最大化来使得模型泛化能力最强。 如上图所…...
R语言中的函数26:polyroot多项式求根函数
目录 介绍函数介绍参数含义 示例 介绍 R语言中的base::polyroot()可以用于对多项式求根,求根的多项式可以是复数域上的。 函数介绍 polyroot(z)该函数利用Jenkins-Traub算法对多项式 p ( x ) p(x) p(x)进行求根,其中 p ( x ) z 1 z 2 x ⋯ z n x…...
2023年辽宁省数学建模竞赛A题铁路车站的安全标线
2023年辽宁省数学建模竞赛 A题 铁路车站的安全标线 原题再现: 在火车站或地铁站台上,离站台边缘 1 米左右的地方都画有一条黄线(或白线),这是为什么呢? 这条线称为安全线(业内称之为安全标线),人们在候车时必须站在安全线以…...
半导体工厂将应用哪些制造创新技术?
半导体工厂是高科技产业的结晶,汇聚了世界上最新的技术。 在半导体的原料硅晶片上绘制设计图纸,不产生误差,准确切割并包装,然后用芯片生产出我们使用的电脑、智能手机、手表等各种电子产品。绝大多数半导体厂都采用一贯的工艺&a…...
[unity]深色模式/浅色模式
这里用的是Windows版的unity,具体版本号如下: 选项的路径如下:Edit—Preferences—General—Editor Theme 然后就可以选是dark还是light了:...
在react中组件间过渡动画如何实现?
一、是什么 在日常开发中,页面切换时的转场动画是比较基础的一个场景 当一个组件在显示与消失过程中存在过渡动画,可以很好的增加用户的体验 在react中实现过渡动画效果会有很多种选择,如react-transition-group,react-motion&…...
解析找不到msvcr100.dll文件的解决方法,4个方法修复msvcr100.dll
msvcr100.dll是Microsoft Visual C 2010运行库的组成部分,一些基于Visual C开发的软件运行时会依赖这个dll文件。出现“找不到msvcr100.dll”的错误提示,往往意味着这个文件在你的计算机系统中丢失或损坏,导致相关程序无法正常运行。以下是找…...
达梦主备部署
达梦主备部署 一.概括1)环境软件下载2)集群规划 二.安装1)安装前2)安装数据库 三.主备机器部署1)初始化数据库(1)主库配置(2)备库配置 2)脱机备份(1)主服务器…...
后期混音效果全套插件Waves 14 Complete mac中文版新增功能
Waves 14 Complete for Mac是一款后期混音效果全套插件,Waves音频插件,内置混响,压缩,降噪和EQ等要素到建模的模拟硬件,环绕声和后期制作工具,包含全套音频效果器,是可以让你使用所有功能。Waves 14 Comple…...
HTML5笔记
前端学习笔记专栏区别于官网中全面的知识讲解,主要记录学习技术栈时对于重点内容的提炼,便于对技术栈知识的快速回顾以及使用 1.canvas元素 内部坐标:坐标均以左上角为(0, 0),单一坐标均作为起始坐标创建对象: <c…...
前端架构师需要解决那些问题
假设你是一个大型后台管理系统的前端架构师,你需要解决那些问题? 1、Ui设计规范 大型系统UI得统一吧?各个业务模块的UI设计得高效吧?那就得有规范,直观的说就是原子设计那套东西。加一堆推荐设计稿。 2、基础组件库…...
使用python快速搭建接口自动化测试脚本实战总结
导读 本文将介绍如何使用python快速进行http/https接口自动化测试脚本搭建,实现自动请求、获取结果、数据对比分析,导出结果到Excel等功能,包括python的requests、pandas、openpyxl等库的基本使用方法。 测试需求介绍 通常,在我…...
android studio 字节码查看工具jclasslib bytecode viewer
jclasslib bytecode viewer 是一款非常好用的.class文件查看工具; jclasslib bytecode editor is a tool that visualizes all aspects of compiled Java class files and the contained bytecode. Many aspects of class files can be edited in the UI. In addit…...
Ubuntu上搭建FTP服务
要在Ubuntu上搭建FTP服务器,可以使用常见的FTP服务器软件如vsftpd(Very Secure FTP Daemon)或ProFTPD。以下是使用vsftpd在Ubuntu上设置FTP服务器的基本步骤: 步骤 1: 安装 vsftpd 打开终端并运行以下命令安装 vsftpd:…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

