Linux应用之构建命令行解释器(bash进程)
目录
1.分析
2.打印输入提示符
3.读取并且处理输入字符串
4.创建子进程并切换
5.bash内部指令
6.完整代码
1.分析
当我们登录服务器的时候,命令行解释器就会自动加载出来。接下来我们就。在命令行中输入指令来达到我们想要的目的。
我们在命令行上输入的是一连串的字符串,那么bash首先要做的就是分析字符串。然后判断是否合法字符串。如果是合法字符串,那么就创建一个子进程,让子进程去切换执行命令,bash分析子进程结果。如果是非法字符串,那么就再次循环,整体嵌套在一个while循环里面。如此循环下去。
2.打印输入提示符

通过观察超级用户和普通用户可以发现提示行主要由三部分构成,用户名,主机名,地址以及特殊符号,用户名和主机名可以从环境变量中获取,主机名就设置为@区别于shell。
#include<iostream>
#include<unistd.h>
#include<stdio.h>
#include<string>
using namespace std;const int MaxSize=1024;char * UsrName;
char * HostName;
char CommandPwd[MaxSize];//打印命令行提示符
void PrintCLPrompt()
{printf("[%s@%s %s]@",UsrName,HostName,CommandPwd);
}//准备工作
void setup()
{UsrName=getenv("USER");HostName=getenv("HOSTNAME");//这里采用C++的string来接收是为了后序处理方便string str=getenv("PWD");string tmp=str.substr(str.rfind("/")+1);//加一去除/字符snprintf(CommandPwd,MaxSize,"%s",tmp.c_str());//格式化输出到数组函数
}int main()
{setup();while(1){PrintCLPrompt();//让程序停在这里方便观察 scanf("%d",NULL);}return 0;
}
此时输出的命令行提示符就在我们的预期之中了

3.读取并且处理输入字符串
读取比较简单,我们只需scanf或者cin即可。( C++兼容C所以在这里读取可以使用C的方式或者是C++的方式,同理输出也可以采用C的方式或者C++的方式哪个方便用哪个)。处理的话我们就把它处理成命令行参数列表以便后续切换进程。

前面代码相同,加上后序调试代码与读取指令即可。
//读取处理指令
char Command[MaxSize];
char * argv[MaxSize];
void ReadDealCommand()
{//读取一行字符串fgets(Command,MaxSize,stdin);int len=strlen(Command)-1;//fegts会把\n也读取到,但这个是不用的字符.Command[len]='\0';//处理字符串int size=0;int prev=-1,cur=0;//预处理,将空格换成\0for(int i=0; i<len; i++){if(Command[i]==' ')Command[i]='\0';}while(cur<len){if(prev == -1 && Command[cur]!='\0'|| Command[prev]=='\0' && Command[cur]!='\0'){argv[size++]=Command+cur;}prev++;cur++;}//argv最后加上NULLargv[size]=NULL;}int main()
{setup();while(1){ //打印提示行PrintCLPrompt();//读取处理指令ReadDealCommand();//检测是否处理成功for(int i=0; argv[i]; i++){printf("argv[%d]:%s\n",i,argv[i]);}}return 0;
}
上述读取一行字符串采用了C语言的fgets函数,当然也可以用C++的getline。使用C++的fgets函数,要注意它会把反斜\n也读取到,在计算字符串的长度时要减一。
将原字符串空格改为\0后,就可以让数组指针直接指向原字符串即可。

其中要注意可能有结尾或者开头带空格的情况。(以下用@代替空格)
ls@-a@-l
@ls@-a@-l
ls@-a@-l@
4.创建子进程并切换
//执行指令
void PreformCommand()
{pid_t id=fork();if(id ==0 ){execvp(argv[0],argv);exit(111);}//父进程int status=0;pid_t rid=wait(&status);if (WIFEXITED(status)){// 子进程正常退出,提取退出状态码int exit_status = WEXITSTATUS(status);// printf("Child process exited normally with status %d\n", exit_status);}else if (WIFSIGNALED(status)) {// 子进程因信号终止,提取信号编号int signal_num = WTERMSIG(status);printf("Child process terminated by signal %d\n", signal_num);}
}int main()
{setup();while(1){ //打印提示行PrintCLPrompt();//读取处理指令ReadDealCommand();//执行指令PreformCommand();}return 0;
}
创建子进程,并让子进程切换到所要执行的程序,父进程接收子进程的退出码即可.由此我们便基本完成了bash程序。

5.bash内部指令
有一些指令是可以直接从环境变量中得到或使用的,就不必再创建子进程了直接在bash里完成指令即可。比如cd,pwd等这些都是bash内部程序。

//执行指令
void PreformCommand()
{//bash内部程序if(strcmp("pwd",argv[0])==0){ printf("%s\n",getenv("PWD"));return ;}else if(strcmp("cd",argv[0])==0){chdir(argv[1]);char cwd[1024];getcwd(cwd,1024);//更新地址string str=cwd;string tmp=str.substr(str.rfind("/")+1);//加一去除/字符snprintf(CommandPwd,MaxSize,"%s",tmp.c_str());//格式化输出到数组函数//修改环境变量string s="PWD=";s+=cwd;snprintf(cwd,MaxSize,"%s",s.c_str());//格式化输出到数组函数 putenv(cwd);//putenv参数要是char*,但c_str()返回的是const char *return ;}pid_t id=fork();if(id ==0 ){execvp(argv[0],argv);//切换不成功返回退出码exit(111);}//父进程int status=0;pid_t rid=wait(&status);if (WIFEXITED(status)){// 子进程正常退出,提取退出状态码int exit_status = WEXITSTATUS(status);// printf("Child process exited normally with status %d\n", exit_status);}else if (WIFSIGNALED(status)) {// 子进程因信号终止,提取信号编号int signal_num = WTERMSIG(status);printf("Child process terminated by signal %d\n", signal_num);}
}int main()
{setup();while(1){ //打印提示行PrintCLPrompt();//读取处理指令ReadDealCommand();//执行指令PreformCommand();}return 0;
}
6.完整代码
最后全部的代码就在这了,上述粘贴可能有错误还望海涵
#include<iostream>
#include<unistd.h>
#include<stdio.h>
#include<string>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
using namespace std;const int MaxSize=1024;char * UsrName;
char * HostName;
char CommandPwd[MaxSize];//打印命令行提示符
void PrintCLPrompt()
{printf("[%s@%s %s]@",UsrName,HostName,CommandPwd);
}//准备工作
void setup()
{UsrName=getenv("USER");HostName=getenv("HOSTNAME");string str=getenv("PWD");string tmp=str.substr(str.rfind("/")+1);//加一去除/字符snprintf(CommandPwd,MaxSize,"%s",tmp.c_str());//格式化输出到数组函数
}//读取处理指令
char Command[MaxSize];
char * argv[MaxSize];
void ReadDealCommand()
{//读取一行字符串fgets(Command,MaxSize,stdin);int len=strlen(Command)-1;//fegts会把\n也读取到,但这个是不用的字符Command[len]='\0';//处理字符串int size=0;int prev=-1,cur=0;//预处理,将空格换成\0for(int i=0; i<len; i++){if(Command[i]==' ')Command[i]='\0';}while(cur<len){if(prev == -1 && Command[cur]!='\0'|| Command[prev]=='\0' && Command[cur]!='\0'){argv[size++]=Command+cur;//.autorelabel printf("%d ",cur);}prev++;cur++;}//argv最后加上NULLargv[size]=NULL;}
//执行指令
void PreformCommand()
{//bash内部程序if(strcmp("pwd",argv[0])==0){ printf("%s\n",getenv("PWD"));return ;}else if(strcmp("cd",argv[0])==0){chdir(argv[1]);char cwd[1024];getcwd(cwd,1024);//更新地址string str=cwd;string tmp=str.substr(str.rfind("/")+1);//加一去除/字符snprintf(CommandPwd,MaxSize,"%s",tmp.c_str());//格式化输出到数组函数//修改环境变量string s="PWD=";s+=cwd;snprintf(cwd,MaxSize,"%s",s.c_str());//格式化输出到数组函数 putenv(cwd);//putenv参数要是char*,但c_str()返回的是const char *return ;}pid_t id=fork();if(id ==0 ){execvp(argv[0],argv);//切换不成功返回退出码exit(111);}//父进程int status=0;pid_t rid=wait(&status);if (WIFEXITED(status)){// 子进程正常退出,提取退出状态码int exit_status = WEXITSTATUS(status);// printf("Child process exited normally with status %d\n", exit_status);}else if (WIFSIGNALED(status)) {// 子进程因信号终止,提取信号编号int signal_num = WTERMSIG(status);printf("Child process terminated by signal %d\n", signal_num);}
}int main()
{setup();while(1){ //打印提示行PrintCLPrompt();//读取处理指令ReadDealCommand();//执行指令PreformCommand();}return 0;
}
相关文章:
Linux应用之构建命令行解释器(bash进程)
目录 1.分析 2.打印输入提示符 3.读取并且处理输入字符串 4.创建子进程并切换 5.bash内部指令 6.完整代码 1.分析 当我们登录服务器的时候,命令行解释器就会自动加载出来。接下来我们就。在命令行中输入指令来达到我们想要的目的。 我们在命令行上输入的…...
php 系统命令执行及绕过
文章目录 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命令执行可以执行命令的函数命令执行绕过利用代码中命令(如ls)执行命令替换过滤过滤特定字符串神技:利用base64编码解码的绕…...
保护大数据的最佳实践方案
在当今数字化时代,保障大数据安全的重要性再怎么强调也不为过。 随着科技的迅猛发展以及对数据驱动决策的依赖日益加深,企业必须将保护其宝贵信息置于首位。 我们将深入探讨保障大数据安全的流程,并讨论关键原则、策略、工具及技术…...
在高流量下保持WordPress网站的稳定和高效运行
随着流量的不断增加,网站的稳定和高效运行变得越来越重要,特别是使用WordPress搭建的网站。流量过高时,网站加载可能会变慢,甚至崩溃,直接影响用户体验和网站正常运营。因此,我们需要采取一些有效的措施&am…...
Redis7——基础篇(二)
前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 基础篇: Redis(一) 接上期内容:上期完成了Redis环境的搭建。下面开始学习Redis常用命令…...
Docker 容器安装 Dify的两种方法
若 Windows 已安装 Docker,可借助 Docker 容器来安装 Dify: 一、方法一 1. 拉取 Dify 镜像 打开 PowerShell 或命令提示符(CMD),运行以下命令从 Docker Hub 拉取 Dify 的镜像(Docker Hub中找到该命令行&…...
golang常用库之-swaggo/swag根据注释生成接口文档
文章目录 golang常用库之-swaggo/swag库根据注释生成接口文档什么是swaggo/swag golang常用库之-swaggo/swag库根据注释生成接口文档 什么是swaggo/swag github:https://github.com/swaggo/swag 参考文档:https://golang.halfiisland.com/community/pk…...
docker中pull hello-world的时候出现报错
Windows下的docker中pull的时候出现下面的错误: PS C:\Users\xxx> docker pull hello-world Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connect…...
NPM环境搭建指南
NPM(Node Package Manager)是 Node.js 的包管理工具,堪称前端开发的基石。本文将手把手教你 在Mac、Windows、Linux三大系统上快速搭建NPM环境,并验证是否成功。 一、Mac系统安装NPM 方法1:通过Homebrew安装ÿ…...
【CSS进阶】常见的页面自适应的方法
在前端开发中,自适应布局(Responsive Design)是一种让网页能够适应不同屏幕尺寸、设备和分辨率的技术。常见的自适应布局方法包括 流式布局、弹性布局(Flexbox)、栅格布局(Grid)、媒体查询&…...
Linux系统配置阿里云yum源,安装docker
配置阿里云yum源 需要保证能够访问阿里云网站 可以先ping一下看看(阿里云可能禁ping,只要能够解析为正常的ip地址即可) ping mirrors.aliyun.com脚本 #!/bin/bash mkdir /etc/yum.repos.d/bak mv /etc/yum.repos.d/*.repo /etc/yum.repos…...
啥是CTF?新手如何入门CTF?网络安全零基础入门到精通实战教程!
CTF是啥 CTF 是 Capture The Flag 的简称,中文咱们叫夺旗赛,其本意是西方的一种传统运动。在比赛上两军会互相争夺旗帜,当有一方的旗帜已被敌军夺取,就代表了那一方的战败。在信息安全领域的 CTF 是说,通过各种攻击手…...
免费搭建个人网站
💡 全程零服务器、完全免费!我的个人站 guoshunfa.com ,正是基于此方案搭建,目前稳定运行。 ✅ vdoing不是基于最新的vuepress2,但是是我目前使用过最好用的主题,完全自动化,只需专心写博客。 …...
网络安全钓鱼邮件测试 网络安全 钓鱼
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 如今,网络安全是一个备受关注的话题,“网络钓鱼”这个词也被广泛使用。 即使您对病毒、恶意软件或如何在线保护自己一无所知,您…...
Rust编程语言入门教程(五)猜数游戏:生成、比较神秘数字并进行多次猜测
Rust 系列 🎀Rust编程语言入门教程(一)安装Rust🚪 🎀Rust编程语言入门教程(二)hello_world🚪 🎀Rust编程语言入门教程(三) Hello Cargo…...
haproxy实现MySQL服务器负载均衡
1.环境准备 准备好下面四台台服务器: 主机名IP角色open-Euler1192.168.121.150mysql-server1openEuler-2192.168.121.151mysql-server2openEuler-3192.168.121.152clientRocky8-1192.168.121.160haproxy 2.mysql服务器配置 1.下载mariadb #下载mariadb [rootop…...
Windows桌面系统管理5:Windows 10操作系统注册表
Windows桌面系统管理0:总目录-CSDN博客 Windows桌面系统管理1:计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2:VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3:Windows 10操作系统部署与使用-CSDN博客 Wi…...
CSDN文章质量分查询系统【赠python爬虫、提分攻略】
CSDN文章质量分查询系统 https://www.csdn.net/qc 点击链接-----> CSDN文章质量分查询系统 <------点击链接 点击链接-----> https://www.csdn.net/qc <------点击链接 点击链接-----> CSDN文章质量分查询系统 <------点击链接 点击链…...
Mysql测试连接失败
解决方案 1 将mysql.exe(C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe)配置到系统环境变量 2 管理员权限启动cmd 输入 3 ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; 4 FLUSH PRIVILEGES;...
DeepSeek(AI)如何赋能智能漏洞扫描与利用的思考
当下,网络安全威胁持续演变,从简单恶意软件传播发展为结合人工智能、大数据分析的APT,对个人、企业及政府关键信息基础设施构成严重挑战。 漏洞作为网络安全薄弱点,数量和种类随软件系统升级与网络架构复杂化急剧增加,…...
社区团购对账程序,订单,货款,分红上链,团长与用户对账透明,无猫腻。
⚠️ 再次强调:这是本地模拟区块链思路的演示程序,用于说明“对账透明化”的技术逻辑,不是金融级或监管级系统。一、实际应用场景描述某社区团购平台存在以下角色:- 平台方:组织商品、结算货款- 团长:负责社…...
从零开始做 TikTok,2026 年最新实操攻略
很多朋友私信问我,想做 TikTok 但不知道怎么入门。这里我整理了一套完整的操作流程,按步骤来就行。### 🔑 为什么选择 TikTok 平台? 1. 海量海外用户,覆盖全球主要市场 2. 新号冷启动难度低,内容即流量 3. …...
百度文库免费获取工具终极指南:三步告别付费墙,轻松保存任何文档
百度文库免费获取工具终极指南:三步告别付费墙,轻松保存任何文档 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 还在为百度文库的付费文档而烦恼吗?每次找到心…...
7-Zip:你的免费数字空间整理大师,让文件压缩变得简单高效
7-Zip:你的免费数字空间整理大师,让文件压缩变得简单高效 【免费下载链接】7z 7-Zip Official Chinese Simplified Repository (Homepage and 7z Extra package) 项目地址: https://gitcode.com/gh_mirrors/7z1/7z 想象一下,你的电脑硬…...
【紧急预警】PHP 9.0协程调度器重大变更!AI聊天机器人状态同步失效风险清单(含7个必修迁移checklist)
更多请点击: https://intelliparadigm.com 第一章:PHP 9.0异步编程与AI聊天机器人对比评测报告的定位与价值 本报告聚焦于 PHP 生态演进的关键拐点——PHP 9.0(预发布技术白皮书阶段)所引入的原生协程调度器(Swoole-n…...
ECS系统调度失衡,Burst不生效,Chunk布局碎片化——DOTS 2.0三大性能暗礁,及工业级绕行方案,仅限首批内测团队验证
更多请点击: https://intelliparadigm.com 第一章:ECS系统调度失衡,Burst不生效,Chunk布局碎片化——DOTS 2.0三大性能暗礁,及工业级绕行方案,仅限首批内测团队验证 在 Unity DOTS 2.0 实际产线部署中&…...
【微电网调度】考虑需求响应的改进的多目标灰狼算法微电网优化调度研究【含Matlab源码 15393期】
💥💥💥💥💥💥💥💥💞💞💞💞💞💞💞💞💞Matlab领域博客之家💞&…...
别再写重复代码了!Spring Boot项目里统一API响应体的3种实用封装方案(含分页)
Spring Boot项目中统一API响应体的高效封装策略与实践 在Web API开发中,统一响应格式是提升团队协作效率和代码可维护性的关键环节。想象一下这样的场景:前端开发者需要对接十几个接口,每个接口返回的数据结构各不相同——有的直接返回裸数据…...
Gymnasium(新版Gym)升级踩坑记:reset()和step()返回值变了,你的强化学习代码还好吗?
Gymnasium升级实战:从API变更到兼容性代码的全方位指南 当你在深夜调试强化学习代码时,突然遇到"ValueError: too many values to unpack (expected 4)"这样的错误,是否感到一阵头皮发麻?这很可能是因为你使用的Gym库已…...
终极游戏模组加载器:3分钟学会安装任何游戏插件
终极游戏模组加载器:3分钟学会安装任何游戏插件 【免费下载链接】Ultimate-ASI-Loader The Ultimate ASI Loader is a proxy DLL that loads custom .asi libraries into any game process. 项目地址: https://gitcode.com/gh_mirrors/ul/Ultimate-ASI-Loader …...
