当前位置: 首页 > news >正文

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.分析 当我们登录服务器的时候&#xff0c;命令行解释器就会自动加载出来。接下来我们就。在命令行中输入指令来达到我们想要的目的。 我们在命令行上输入的…...

php 系统命令执行及绕过

文章目录 php的基础概念php的基础语法1. PHP 基本语法结构2. PHP 变量3.输出数据4.数组5.超全局变量6.文件操作 php的命令执行可以执行命令的函数命令执行绕过利用代码中命令&#xff08;如ls&#xff09;执行命令替换过滤过滤特定字符串神技&#xff1a;利用base64编码解码的绕…...

保护大数据的最佳实践方案

在当今数字化时代&#xff0c;保障大数据安全的重要性再怎么强调也不为过。 随着科技的迅猛发展以及对数据驱动决策的依赖日益加深&#xff0c;企业必须将保护其宝贵信息置于首位。 我们将深入探讨保障大数据安全的流程&#xff0c;并讨论关键原则、策略、工具及技术&#xf…...

在高流量下保持WordPress网站的稳定和高效运行

随着流量的不断增加&#xff0c;网站的稳定和高效运行变得越来越重要&#xff0c;特别是使用WordPress搭建的网站。流量过高时&#xff0c;网站加载可能会变慢&#xff0c;甚至崩溃&#xff0c;直接影响用户体验和网站正常运营。因此&#xff0c;我们需要采取一些有效的措施&am…...

Redis7——基础篇(二)

前言&#xff1a;此篇文章系本人学习过程中记录下来的笔记&#xff0c;里面难免会有不少欠缺的地方&#xff0c;诚心期待大家多多给予指教。 基础篇&#xff1a; Redis&#xff08;一&#xff09; 接上期内容&#xff1a;上期完成了Redis环境的搭建。下面开始学习Redis常用命令…...

Docker 容器安装 Dify的两种方法

若 Windows 已安装 Docker&#xff0c;可借助 Docker 容器来安装 Dify&#xff1a; 一、方法一 1. 拉取 Dify 镜像 打开 PowerShell 或命令提示符&#xff08;CMD&#xff09;&#xff0c;运行以下命令从 Docker Hub 拉取 Dify 的镜像&#xff08;Docker Hub中找到该命令行&…...

golang常用库之-swaggo/swag根据注释生成接口文档

文章目录 golang常用库之-swaggo/swag库根据注释生成接口文档什么是swaggo/swag golang常用库之-swaggo/swag库根据注释生成接口文档 什么是swaggo/swag github&#xff1a;https://github.com/swaggo/swag 参考文档&#xff1a;https://golang.halfiisland.com/community/pk…...

docker中pull hello-world的时候出现报错

Windows下的docker中pull的时候出现下面的错误&#xff1a; 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&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;堪称前端开发的基石。本文将手把手教你 在Mac、Windows、Linux三大系统上快速搭建NPM环境&#xff0c;并验证是否成功。 一、Mac系统安装NPM 方法1&#xff1a;通过Homebrew安装&#xff…...

【CSS进阶】常见的页面自适应的方法

在前端开发中&#xff0c;自适应布局&#xff08;Responsive Design&#xff09;是一种让网页能够适应不同屏幕尺寸、设备和分辨率的技术。常见的自适应布局方法包括 流式布局、弹性布局&#xff08;Flexbox&#xff09;、栅格布局&#xff08;Grid&#xff09;、媒体查询&…...

Linux系统配置阿里云yum源,安装docker

配置阿里云yum源 需要保证能够访问阿里云网站 可以先ping一下看看&#xff08;阿里云可能禁ping&#xff0c;只要能够解析为正常的ip地址即可&#xff09; 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 的简称&#xff0c;中文咱们叫夺旗赛&#xff0c;其本意是西方的一种传统运动。在比赛上两军会互相争夺旗帜&#xff0c;当有一方的旗帜已被敌军夺取&#xff0c;就代表了那一方的战败。在信息安全领域的 CTF 是说&#xff0c;通过各种攻击手…...

免费搭建个人网站

&#x1f4a1; 全程零服务器、完全免费&#xff01;我的个人站 guoshunfa.com &#xff0c;正是基于此方案搭建&#xff0c;目前稳定运行。 ✅ vdoing不是基于最新的vuepress2&#xff0c;但是是我目前使用过最好用的主题&#xff0c;完全自动化&#xff0c;只需专心写博客。 …...

网络安全钓鱼邮件测试 网络安全 钓鱼

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 如今&#xff0c;网络安全是一个备受关注的话题&#xff0c;“网络钓鱼”这个词也被广泛使用。 即使您对病毒、恶意软件或如何在线保护自己一无所知&#xff0c;您…...

Rust编程语言入门教程(五)猜数游戏:生成、比较神秘数字并进行多次猜测

Rust 系列 &#x1f380;Rust编程语言入门教程&#xff08;一&#xff09;安装Rust&#x1f6aa; &#x1f380;Rust编程语言入门教程&#xff08;二&#xff09;hello_world&#x1f6aa; &#x1f380;Rust编程语言入门教程&#xff08;三&#xff09; Hello Cargo&#x1f…...

haproxy实现MySQL服务器负载均衡

1.环境准备 准备好下面四台台服务器&#xff1a; 主机名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&#xff1a;总目录-CSDN博客 Windows桌面系统管理1&#xff1a;计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2&#xff1a;VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3&#xff1a;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)如何赋能智能漏洞扫描与利用的思考

当下&#xff0c;网络安全威胁持续演变&#xff0c;从简单恶意软件传播发展为结合人工智能、大数据分析的APT&#xff0c;对个人、企业及政府关键信息基础设施构成严重挑战。 漏洞作为网络安全薄弱点&#xff0c;数量和种类随软件系统升级与网络架构复杂化急剧增加&#xff0c…...

社区团购对账程序,订单,货款,分红上链,团长与用户对账透明,无猫腻。

⚠️ 再次强调&#xff1a;这是本地模拟区块链思路的演示程序&#xff0c;用于说明“对账透明化”的技术逻辑&#xff0c;不是金融级或监管级系统。一、实际应用场景描述某社区团购平台存在以下角色&#xff1a;- 平台方&#xff1a;组织商品、结算货款- 团长&#xff1a;负责社…...

从零开始做 TikTok,2026 年最新实操攻略

很多朋友私信问我&#xff0c;想做 TikTok 但不知道怎么入门。这里我整理了一套完整的操作流程&#xff0c;按步骤来就行。### &#x1f511; 为什么选择 TikTok 平台&#xff1f; 1. 海量海外用户&#xff0c;覆盖全球主要市场 2. 新号冷启动难度低&#xff0c;内容即流量 3. …...

百度文库免费获取工具终极指南:三步告别付费墙,轻松保存任何文档

百度文库免费获取工具终极指南&#xff1a;三步告别付费墙&#xff0c;轻松保存任何文档 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 还在为百度文库的付费文档而烦恼吗&#xff1f;每次找到心…...

7-Zip:你的免费数字空间整理大师,让文件压缩变得简单高效

7-Zip&#xff1a;你的免费数字空间整理大师&#xff0c;让文件压缩变得简单高效 【免费下载链接】7z 7-Zip Official Chinese Simplified Repository (Homepage and 7z Extra package) 项目地址: https://gitcode.com/gh_mirrors/7z1/7z 想象一下&#xff0c;你的电脑硬…...

【紧急预警】PHP 9.0协程调度器重大变更!AI聊天机器人状态同步失效风险清单(含7个必修迁移checklist)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;PHP 9.0异步编程与AI聊天机器人对比评测报告的定位与价值 本报告聚焦于 PHP 生态演进的关键拐点——PHP 9.0&#xff08;预发布技术白皮书阶段&#xff09;所引入的原生协程调度器&#xff08;Swoole-n…...

ECS系统调度失衡,Burst不生效,Chunk布局碎片化——DOTS 2.0三大性能暗礁,及工业级绕行方案,仅限首批内测团队验证

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;ECS系统调度失衡&#xff0c;Burst不生效&#xff0c;Chunk布局碎片化——DOTS 2.0三大性能暗礁&#xff0c;及工业级绕行方案&#xff0c;仅限首批内测团队验证 在 Unity DOTS 2.0 实际产线部署中&…...

【微电网调度】考虑需求响应的改进的多目标灰狼算法微电网优化调度研究【含Matlab源码 15393期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;Matlab领域博客之家&#x1f49e;&…...

别再写重复代码了!Spring Boot项目里统一API响应体的3种实用封装方案(含分页)

Spring Boot项目中统一API响应体的高效封装策略与实践 在Web API开发中&#xff0c;统一响应格式是提升团队协作效率和代码可维护性的关键环节。想象一下这样的场景&#xff1a;前端开发者需要对接十几个接口&#xff0c;每个接口返回的数据结构各不相同——有的直接返回裸数据…...

Gymnasium(新版Gym)升级踩坑记:reset()和step()返回值变了,你的强化学习代码还好吗?

Gymnasium升级实战&#xff1a;从API变更到兼容性代码的全方位指南 当你在深夜调试强化学习代码时&#xff0c;突然遇到"ValueError: too many values to unpack (expected 4)"这样的错误&#xff0c;是否感到一阵头皮发麻&#xff1f;这很可能是因为你使用的Gym库已…...

终极游戏模组加载器:3分钟学会安装任何游戏插件

终极游戏模组加载器&#xff1a;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 …...