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

Shell进程替换,自定义Shell解释器——字符串库函数灵活操作!

@bit::Shadow
✧(≖ ◡ ≖✿

目录

进程程序替换

“程序”怎么理解?

shell内程序替换的接口

6+1

命名规律:

第一个参数path/file

which与where查询位置

自定义shell命令解释器

0.设置环境变量

1.命令行提示符

2.获取用户输入

strtok()字符串截取函数

例:

执行结果:

myshell模块功能实现:

3.指令执行(可优化封装)

strcmp()

strcpy()

dest要求:

strcat()

☆☆☆snprintf()

参数

返回值:

使用实例:

myshell指令执行功能


进程程序替换

定义:进程程序替换指使用一个新的程序(可执行文件),替换当前进程的代码数据 栈 堆 内存段等,但保留原进程的PID、某些环境及文件描述符等信息。替换完成后程序执行新的代码块,新代码块执行完成后,原代码块不再执行

“程序”怎么理解?

一个存储在硬盘上的,静态的、可执行的指令和数据的集合,它是一个/多个死的文件

shell内程序替换的接口

6+1

接口有6+1个前六个复用第七个,前六个作为库函数最后一个作为系统调用。

前六个:

后一个:

7者一旦返回(-1)代表执行失败。

观察发现它们的组成方式都是:“exec”+…… 参数几乎是一致的,实际上七者对应参数的功能都是一致的。

命名规律:

l(list) vs v(vector):指明命令行参数的传递方式

  • l :采用参数列表的形式。像execl("usr/bin/ls", "ls", "-l", NULL)这样每个参数作为单独的参数依次列出,最后以NULL结尾。
  • v:采用数组的方式。先将所有参数存储到一个指针数组内(包含NULL),然后把数组地址传递给函数。

p(path):指明可执行文件的查找方式

  • 带p只需提供文件名如ls,函数会在自动环境变量PATH中搜索。
  • 不带p:必须提供完整的文件路径(如:/usr/bin/ls)。

e(environment):指明环境变量的来源

  • 带e:可以传入一个envp[]数组来自定义新程序的环境变量。(很少使用)
  • 不带e:新程序会默认继承当前进程的环境变量。

第一个参数path/file

path:文件路径,使用这个路径查找可执行文件名,因此是完整的文件路径。
file:可以加路径也可以不加路径,直接输入指令名称使得从环境变量中自动寻找指令但是要将后续的指令执行全部规范写出,不可因第一个指令而省略。

以execl()为例:

int execl(const char*path, const char* arg0, ……, (char*)0);
which与where查询位置
where所有找到的匹配项(包括别名、二进制、源码、帮助文档)更全面,适合查看命令的“所有存在形式”
which只输出第一个匹配的二进制文件路径更简洁,只告诉你会执行哪个

第一个参数路径path的寻找:

由“l”推出参数列表:

运行:

运行结果:

file参数可直接写指令:

数组char* argv[]:


自定义shell命令解释器

设计导图(图片过大 无法全部呈现->smlShell仓库)

0.设置环境变量

由于无法获取系统层面的环境变量只能通过const char** environ来拷贝+putenv();

//设置环境变量 char* enVr[129];//内部存储char*类型"lll" void EnvInit() { memset(enVr, 0, sizeof(enVr)); // 好的习惯 extern char** environ;//内部存储char**的数据类型environ[] "lll" for(int i = 0;environ[i];i++)//i至多为20 { enVr[i]=(char*)malloc(strlen(environ[i])+1); //enVr[i]=(char*)malloc(sizeof(strlen(environ[i])+1)); strcpy(enVr[i],environ[i]); putenv(enVr[i]); } }

1.命令行提示符

char* getenv(const char* EnvmVar); // 参数为环境变量名称返回对应内容

//命令行 void CoutCommandLine() { std::cout << "[" << getenv("USER") \ << "@" << getenv("HOSTNAME") << " " << getenv("PWD") << "]"; if(strcmp(getenv("USER"),"root")==0) std::cout << "# ";//err当相等时返回0 else std::cout << "$ "; }

2.获取用户输入

strtok()字符串截取函数

#include <string.h> char *strtok(char *str, const char *delim);

char* strtok(char* str, const char* delim); // 用于分割字符串,delim为分割单位

具体功能:将原串delim处变作'\0',并返回分割得到的子串。

若想要多次分割(对同一字符串),第一个参数必须传入NULL

例:
#include <stdio.h> #include <string.h> int main() { char path[] = "/home/user/documents/file.txt"; // 分割路径 char *token = strtok(path, "/"); while (token != NULL) { printf("目录/文件: %s\n", token); token = strtok(NULL, "/"); } return 0; }
执行结果:

目录/文件: home
目录/文件: user
目录/文件: documents
目录/文件: file.txt

myshell模块功能实现:
//指令解析 void CommandParsed() { //std::cout << CommandLine ; //1.不接纳数组传参的直接淘汰 , //2.file和path选file无需位置指定 //3.无需传环境变量所以选择 //int execvp(const char* file, char *const argv[]) //第一个命令的截取 若一个命令由多部分组成该怎么办?怎么区分指令与选项 int i = 0; CommandStr[i++]=strtok(CommandLine," ");//自动将分隔符替换为'\0' //截取剩余选项的主逻辑 while((bool)(CommandStr[i++]=strtok(NULL," "))); }

3.指令执行(可优化封装)

strcmp()

#include <string.h> int strcmp(const char *str1, const char *str2);

int strcmp(const char* str1, const char* str2);

//字符串比较函数,字符串相等返回0。 // 注意:由于返回0所以if(!strcmp(str1, str2)) ;

strcpy()

#include <string.h> char *strcpy(char *dest, const char *src);

功能:将src复制到dest

dest要求:
要求说明违反后果
有效的内存地址不能是NULL 或野指针段错误,程序崩溃
可写内存不能是只读内存(如字符串常量)段错误或未定义行为
足够的空间至少strlen(src) + 1字节缓冲区溢出,安全漏洞
已分配空间不能是未初始化的指针未定义行为,崩溃

strcat()

对dest要求可以找到'\0'。

#include <string.h> char *strcat(char *dest, const char *src);

☆☆☆snprintf()

作为字符串拷贝转移最安全的函数

#include<stdio.h> int snprintf(char* str, size_t size, const char* format, ...);
参数
  • str:目标缓冲区

  • size:缓冲区大小(字节数)

  • format:格式化字符串

  • ...:可变参数

返回值:
  • 成功时:返回应该写入的字符数(不包括'\0')。
  • 失败时:返回负数。

关键特性

  • 自动添加'\0'结尾

  • 不会溢出(超过size-1的内容被截断)

  • 可替代strcpystrcat

使用实例:
#include <stdio.h> int main() { char buffer[20]; // 基本使用 snprintf(buffer, sizeof(buffer), "Hello"); printf("%s\n", buffer); // Hello }

myshell指令执行功能

//指令执行 void CommandRun() { //"ls" "ls" "-a" "-l" NULL if(strcmp(CommandStr[0],"cd")==0) { if(!strcmp(CommandStr[1],getenv("HOME"))) strcpy(getenv("PWD"),getenv("HOME")); else strcpy(getenv("PWD"),CommandStr[1]); } else if(strcmp(CommandStr[0],"echo")==0) { //echo “字符串” 环境变量/本地变量 $? std::string s = CommandStr[1]; //std::cout<<s; if(s=="$?") { std::cout << exitCode << std::endl; } else if(s[0]=='$') { //CommandStr = "$PATH" std::string s1 = s.substr(1); std::cout << getenv(s1.c_str()) << std::endl; } else{ std::cout << s << std::endl; } } else if(strcmp(CommandStr[0],"env")==0) { for(int i =0;enVr[i];i++) std::cout << enVr[i] << std::endl; std::cout << std::endl << std::endl; } else execvp(CommandStr[0],CommandStr); }

感谢观看
多多关注

http://www.jsqmd.com/news/870012/

相关文章:

  • 2026北京奢侈品回收全攻略:六家专业平台一站式变现指南 - 薛定谔的梨花猫
  • 免费开源神器:SMUDebugTool让你轻松掌控AMD Ryzen处理器的秘密
  • 海强金诺运营模式好不好?哪个口碑好? - 工业品牌热点
  • Mac NTFS读写终极指南:Free NTFS for Mac完整解决方案
  • 2026昆明装修公司实测推荐:口碑与实力兼具,装修避坑优选榜单 - GEO排行榜
  • Hermes Agent对接Taotoken自定义Provider的配置要点详解
  • 2026定西市黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • 北京物业保洁加停车管理公司推荐与性价比解析 - 工业品牌热点
  • 2026 成都名牌包包回收 TOP 榜单:合扬领衔,五大正规机构口碑爆棚 - 李宏哲1
  • Office RibbonX Editor:免费开源Office界面定制终极解决方案
  • 哈尔滨汽车音响改装|奥迪Q5升级法国劲浪全套音响,音质直接越级提升!哈尔滨奥迪专用音响改装方案 适配奥迪A4L、奥迪A6L、奥迪A8L、奥迪Q7、奥迪Q5 - 木火炎
  • CANN-ops-transformer-给昇腾NPU贡献一个大模型算子要走几步
  • Beyond Compare 5授权密钥生成器:一键激活与完整技术解析
  • 洗地车专业厂家推荐哪家比较靠谱? - 工业推荐榜
  • 2026东安县黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • CANN-ops-transformer-从输入到输出昇腾NPU跑了多少个融合算子
  • 丽水黄金回收哪家靠谱 六家门店实测对比长悦回收价高秤准 - 专业黄金回收
  • 2026达县黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • SSCom串口调试助手:跨越平台壁垒的硬件通信解决方案
  • 抖音视频批量下载终极指南:5分钟搞定去水印与合集下载
  • 2026年口碑好的商场电动天棚帘批发价格推荐 - 工业推荐榜
  • ncmdumpGUI:一键解密网易云音乐NCM文件,让音乐重获自由
  • 武汉皓瑞通风设备:东西湖专业的风机维修公司怎么联系 - LYL仔仔
  • 2026东莞市黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • 2026大方县黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • 干货!有实力的环戊烷发泡机源头厂家全解析 - 工业推荐榜
  • linux基础与应用 linux系统常用技巧
  • 2026东源县黄金回收避坑指南;闲置黄金变现;认准铭润金银回收,诚信靠谱 - 亦辰小黄鸭
  • 让中国开源的声音被全球听见——开源社诚邀您参与Linux基金会开源商业化调研
  • 开源vs商业软件:中小企业技术选型的性价比计算