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

网站集约化建设的意义出售淘宝店铺的平台

网站集约化建设的意义,出售淘宝店铺的平台,做网页价格,建设摩托车官网官方网站Linux编写一个极简版本的Shell #x1f4df;作者主页#xff1a;慢热的陕西人 #x1f334;专栏链接#xff1a;Linux #x1f4e3;欢迎各位大佬#x1f44d;点赞#x1f525;关注#x1f693;收藏#xff0c;#x1f349;留言 本博客主要内容在Linux环境下#xff…Linux编写一个极简版本的Shell 作者主页慢热的陕西人 专栏链接Linux 欢迎各位大佬点赞关注收藏留言 本博客主要内容在Linux环境下简易实现了一个Shell顺便讲解和实现了一些内建命令 文章目录 Linux编写一个极简版本的Shell①读取命令行②父子进程框架③切割命令行④子进程借用分割的结果来替换程序⑤优化⑥内建命令(重要) 首先我们观察到 bash的命令行提示符[用户名主机名 当前目录] [milavm-5wklnbmaja demo1] 所以我们无限循环去打印这个命令行提示符 #includestdio.h #includeunistd.h int main() { while(1) { printf([xuptmy_machine currpath]#); //这里因为我们不能加换行所以得刷新缓冲区 fflush(stdout); sleep(1); } return 0; } 运行效果 ①读取命令行 接下来我们就要获取命令输入的命令行参数 我们创建一个字符数组用来专门存放用户输入的命令行 #define MAX 1024 //因为命令行最长支持到1024 char commondstr[MAX] {0};我们用fgets来获取命令行 fgets(commondstr, sizeof(commondstr), stdin); 我们测试一下 结果正常但是我们的命令重新被打印的时候多打印了一个换行符因为fgets读取了换行符并且存储到了commondstr中了. [milavm-5wklnbmaja demo1]$ ./myshell [xuptmy_machine currpath]#ls -a ls -a 解决方案 commondstr[strlen(commondstr) - 1] \0;//处理fget获取了换行符的问题 运行结果 ②父子进程框架 这个时候我们就需要用到子进程了因为执行命令行的时候需要用到程序替换那么如果我们用父进程的话直接就全崩掉了。 每次输入命令都把命令交给子进程去执行而父进程去等待子进程就好了 pid_t id fork(); assert(id 0); (void) id; //和上面的处理原因一样 if(id 0) { //child } int status 0; waitpid(id, status, 0); 在子进程执行之前我们先要将用户输入进来的命令行进行拆分 ③切割命令行 切割的原理很简单我们只需要把命令行中间的空格变成\0即可。 ls -a -l ---- ls\0-a\0-l; 这个时候我们要引入一个C库提供的函数strtok,它是一个专门用来分隔字符串的函数。 我们需要封装一下这个函数来达到为我们分割命令行的目的 注意strtok函数第二次切割的时候只需要传入NULL即可。 int split(char* commondstr, char* argv[]) { assert(commondstr); assert(argv); argv[0] strtok(commondstr, SEP); int i 1; while((argv[i] strtok(NULL, SEP))); // { // argv[i] strtok(NULL, SEP); // if(argv[i] NULL) break; // i; // } //表示切割成功 return 0; } main函数内部这样去调用分割函数 int n split(commondstr, argv);//等于0表示切割成功if(n ! 0) continue;//DebugPrint(argv); 我们再设计一个函数来打印我们切割的结果查看我们切割的结果是否正确 void DebugPrint(char* argv[]) {for(int i 0; argv[i]; i){printf(%d : %s\n, i, argv[i]);} } 运行结果 ④子进程借用分割的结果来替换程序 因为我们用split函数将命令行分装到argv字符串指针数组内部了所以我们只能用带v的加载函数。 另外因为我们不能固定路径所以我们也只能用带p的。 所以综上我们的加载函数就选择到了execvp函数 在子进程内部调用 if(id 0) { //child execvp(argv[0], argv); exit(0); } 那么这时候我们在运行一下 ⑤优化 我们看到我们在用bash提供的ls的时候它产生的结果是带有颜色的。 但是我们自己实现的简易Shell是没有颜色的那么这到底是为什么 我们which ls查看一下原来系统在ls后边面追加了一个参数--colorauto; 那么我们也可以对我们的简易Shell进行一些优化让他支持这样的显示 我们只需要在代码中特判一下即可 if(strcmp(argv[0], ls) 0) { //先找到末尾 int pos 0; while(argv[pos]) pos; //追加color参数 argv[pos] (char*)--colorauto; //安全处理 pos; argv[pos] NULL; }运行效果 ⑥内建命令(重要) 1内建命令的概念 —首先我们先明确一下内建命令/内置命令的概念,就是让我们bash自己执行的命令我们称之为内建命令/内置命令。 2cd命令 当我们在我们的简易Shell中切换目录时 我们发现不论我们怎么切换目录结果都是目录没有变化**原因是我们是在子进程中运行这些命令行的**进程具有独立性。其实我们切换目录是切换了子进程的目录但是父进程也就是我们pwd显示的目录却没有任何变化,并且这里其实pwd的也是子进程的当前目录但是因为子进程在执行完cd命令后就被exit了。当我们再执行pwd的时候是一个新的子进程在帮我们完成这个命令因为我们之前cd没有改变父进程的当前目录那么新创建的子进程的目录也就变成了和父进程一样的所以看起来我们就是没有改变当前目录一样。 所以这里的cd命令我们要在父进程中交给一个函数chdir()来让我们的bash来执行: 代码 //当我们输入cd命令的时候 if(strcmp(argv[0], cd) 0) { if(argv[1] ! NULL) chdir(argv[1]); continue; } 运行结果 3export命令 此外不止我们的cd包括我们当时去在bash中执行我们的export添加环境变量的时候实际上是添加到我们的bash内部的那么如果我们的简易Shell去把这个命令交给我们的子进程去执行了那么就不太合适了应该让我们的父进程自行去执行这个命令 所以我们依旧采用内建命令的方式 //当我们输入export命令时 if(strcmp(argv[0], export) 0) { //我们把这个环境变量存储在我们自己设定的数组内部 if(argv[1] ! NULL) { strcpy(myenv[env_index], argv[1]); //再将数组内部的环境变量放到父进程的环境变量中 putenv(myenv[env_index]); } } 我们尝试测试一下 最终我们找到了 但是我们的env打印的好像是子进程的环境变量这似乎不是我们想要的我们应该想要的是父进程的环境变量所以我们再做一下处理 我们自行实现一个函数去打印我们的环境变量 void PrintEnv(){extern char **environ;for(int i 0; environ[i]; i){printf(%d:%s\n,i, environ[i]);}}//当我们查看环境变量的时候if(strcmp(argv[0], env) 0){PrintEnv();continue; } 运行效果 所以其实我们之前学习的几乎所有的环境变量相关的命令都是内建命令。 我们在将echo支持成内建命令 //当我们echo的时候if(strcmp(argv[0], echo) 0){//先确认一下echo后面第一个跟的是$if(argv[1][0] $){char* env_ret getenv(argv[1] 1); if(env_ret ! NULL){printf(%s%s\n, argv[1] 1, env_ret);}}continue;} 运行结果 既然支持了环境变量的查询我们再来顺便支持一下进程退出码的支持也就是我们的echo $? //当我们echo的时候 if(strcmp(argv[0], echo) 0) { //先确认一下echo后面第一个跟的是$ if(argv[1][0] $) { if(argv[1][1] ?) { printf(%d\n, last_exit); continue; } else { char* env_ret getenv(argv[1] 1); if(env_ret ! NULL) printf(%s%s \n, argv[1] 1, env_ret); } } int status 0;pid_t ret waitpid(id, status, 0);if(ret 0){ last_exit WEXITSTATUS(status);//last_exit我们放在main函数里但不要放在循环里他要长期保留。} 测试结果 ⑦代码汇总 #includestdio.h #includeunistd.h #includeassert.h #includestring.h #includestdlib.h #includesys/types.h #includesys/wait.h//因为命令行最长支持到1024 #define MAX 1024 //限制最多切割为64段 #define ARGC 64#define SEP int split(char* commondstr, char* argv[]) {assert(commondstr);assert(argv);argv[0] strtok(commondstr, SEP);int i 1;while((argv[i] strtok(NULL, SEP))); // { // argv[i] strtok(NULL, SEP); // if(argv[i] NULL) break; // i; // }//表示切割成功return 0; }void PrintEnv() {extern char **environ;for(int i 0; environ[i]; i){printf(%d:%s\n,i, environ[i]);} }void DebugPrint(char* argv[]) {for(int i 0; argv[i]; i){ printf(%d : %s\n, i, argv[i]);} }int main() {int last_exit 0; //存储上一个进程的退出码int env_index 0; //环境变量数组的下标char myenv[32][64];while(1){//每次进来都初始化一下char commondstr[MAX] {0};char* argv[ARGC] {NULL};printf([xuptmy_machine currpath]#);fflush(stdout);//这里因为我们不能加换行所以得刷新缓冲区char* s fgets(commondstr, sizeof(commondstr), stdin); assert(s);(void)s;//保证在release发布的时候因为assert去掉而导致s没有被使用过而产生的告警什么都没做充当一次使用commondstr[strlen(commondstr) - 1] \0; //解决了fgets读入换行符的问题int n split(commondstr, argv);//等于0表示切割成功if(n ! 0) continue;//DebugPrint(argv);//当我们输入export命令时if(strcmp(argv[0], export) 0){//我们把这个环境变量存储在我们自己设定的数组内部if(argv[1] ! NULL)strcpy(myenv[env_index], argv[1]); //再将数组内部的环境变量放到父进程的环境变量中putenv(myenv[env_index]);}}//当我们查看环境变量的时候if(strcmp(argv[0], env) 0){PrintEnv();continue; }//当我们echo的时候if(strcmp(argv[0], echo) 0){//先确认一下echo后面第一个跟的是$if(argv[1][0] $){ if(argv[1][1] ?){printf(%d\n, last_exit); continue;}else{char* env_ret getenv(argv[1] 1);if(env_ret ! NULL) printf(%s%s \n, argv[1] 1, env_ret);}}continue;}//当我们输入cd命令的时候if(strcmp(argv[0], cd) 0){if(argv[1] ! NULL) chdir(argv[1]);continue;} //当我们输入ls命令的时候if(strcmp(argv[0], ls) 0){//先找到末尾int pos 0;while(argv[pos]) pos;//追加color参数argv[pos] (char*)--colorauto;//安全处理pos;argv[pos] NULL;}pid_t id fork();assert(id 0);(void) id; //和上面的处理原因一样if(id 0) {//childexecvp(argv[0], argv);exit(0);}int status 0;pid_t ret waitpid(id, status, 0);if(ret 0){last_exit WEXITSTATUS(status);} // printf(%s\n, commondstr);} return 0; } 到这本篇博客的内容就到此结束了。 如果觉得本篇博客内容对你有所帮助的话可以点赞收藏顺便关注一下 如果文章内容有错误欢迎在评论区指正
http://www.dnsts.com.cn/news/235694.html

相关文章:

  • 安徽住房与城乡建设部网站做一个网站需要哪些
  • 杭州设计网站的公司网站留言自动短信提醒
  • 北京制卡厂家做卡公司北京制卡网站_北京制卡_北京 去114网掘金网站建设
  • 免费速建网站内蒙古网站建设电话
  • 网站后台路径搭建平台的目的和意义是什么
  • 做淘宝网站需要多少钱安徽建设厅官方网站
  • 百度站长工具使用方法叙述一个网站的建设过程
  • 同和网站建设wordpress版型
  • 烟台做网站wordpress站点实例
  • 手机网站开发需要哪些人网站服务器怎么维护
  • 成都建设网站那家好互联网广告代理商
  • 哪里有网站推广软件个人网站备案注销
  • 医院 网站后台管理市场营销活动策划方案
  • 网上做设计的网站南昌租房网
  • 南京城乡建设局网站外贸平台推广公司
  • 重庆建设工程监督管理局网站淘宝怎么做引流和推广
  • 网站规划与设计大作业网销是什么该怎么做
  • 购买网站空间后怎么做网站中文通用网址域名
  • 企业网站群建设dede如何手机网站和电脑网站的数据同步更新
  • 网站页面怎么做地图公司简介模板免费文字版
  • 哪些网站是php免费云服务器官网
  • 网站怎么做图片栏目企业微信crm
  • 为什么企业建设银行网站打不开昆山网络推广公司
  • 建立自己网站我想给企业做网站怎么做
  • 免费网站推广平台wordpress mysql数据库备份
  • python做网站好不好网站建设与管理用什么软件有哪些内容
  • 绑定网站app软件商店
  • 郑州企业网络推广公司如何做网站布局优化
  • 直播间 网站建设网站开发教程云盘
  • 帝国cms企业门户网站仿站视频教程 网盘济南有做五合一网站公司