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

网站开发方法是什么张家港网站关键词优化

网站开发方法是什么,张家港网站关键词优化,网页游戏开发语言,中国国家人事人才培训网目录 一、自动化构建工具(makefile) 二、输出提示符 三、获取用户输入的数据 四、将用户输入的指令字符串进行分割: 五、执行用户输入的命令 六、发现cd命令用不了(内建命令) 原因在于: 七、处理内…

目录

一、自动化构建工具(makefile)

二、输出提示符

三、获取用户输入的数据

四、将用户输入的指令字符串进行分割:

五、执行用户输入的命令

六、发现cd命令用不了(内建命令)

原因在于:

七、处理内建命令cd:

八、存在一个小问题:

八、处理内建命令export

九、获取最近一次进程的退出码

十、处理内建命令echo

十一、让ls指令输出的内容带上颜色

十二、完整代码


上一章节我们学习了程序替换,现在我们就可以通过程序替换来模拟实现shell命令行;

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家

点击跳转到网站

一、自动化构建工具(makefile)

myprocess:myshell.cgcc -o $@ $^ -g -std=c99
.PHONY:clean
clean:rm -f myprocess

二、输出提示符

我们在命令行终端处时,一般会有这个输出提示符:

#include<stdio.h>
#include<stdlib.h>//获取主机名
const char* HostName()
{char* hostname = getenv("HOSTNAME");if(hostname)return hostname;else return "None";
}//获取当前登录的用户名
const char* UserName()
{char* username = getenv("USER");if(username)return username;else return "None";
}//获取当前工作目录
const char* CurrentWorkDir()
{
char* currentworkdir = getenv("PWD");if(currentworkdir)return currentworkdir;else return "None";
}int main()
{//输出提示符printf("[%s@%s %s]$ ",UserName(),HostName(),CurrentWorkDir());return 0;
}

三、获取用户输入的数据

void Interactive(char out[],int size)
{fgets(out,SIZE,stdin);//stdin是标准输入流,意思就是从键盘获取数据保存到commandline中out[strlen(out)-1] = '\0';//因为fgets会读取换行符,所以这步我们去掉换行。
}int main()
{//输出提示符printf("[%s@%s %s]$ ",UserName(),HostName(),CurrentWorkDir());//获取用户输入的命令char commandline[SIZE];Interactive(commandline,SIZE);printf("test:%s\n",commandline);return 0;
}

四、将用户输入的指令字符串进行分割:


//对字符串进行分割
void Split(char in[])
{int i = 0;argv[i++] = strtok(in,SEP);//对字符串commandline以空格作为分隔符进行切割,"ls -a -l"while(argv[i++] = strtok(NULL,SEP));//进行第二次切割时,strtok第一个参数需要传入NULL。
}int main()
{//1、输出提示符printf("[%s@%s %s]$ ",UserName(),HostName(),CurrentWorkDir());//2、获取用户输入的命令char commandline[SIZE];Interactive(commandline,SIZE);printf("test:%s\n",commandline);//3、对命令行字符串进行切割Split(commandline);return 0;
}

五、执行用户输入的命令

执行命令我们是用程序替换的原理,去执行对应的命令,而程序替换过后,就不会再执行之后的代码,为了避免这一点,所以我们创建子进程取进行程序替换。

void Execute()
{//因为程序替换后,不会在执行之后的代码,所以这里创建子进程去执行最合适pid_t id = fork();if(id == 0){//子进程通过程序替换执行命令execvp(argv[0],argv);exit(1);}//父进程进行等待pid_t rid = waitpid(id,NULL,0);printf("run done,rid: %d\n",rid);
}int main()
{//1、输出提示符printf("[%s@%s %s]$ ",UserName(),HostName(),CurrentWorkDir());//2、获取用户输入的命令char commandline[SIZE];Interactive(commandline,SIZE);printf("test:%s\n",commandline);//3、对命令行字符串进行切割Split(commandline);//4、执行分割好的命令Execute();return 0;
}

这样我们就能运行起来单次命令了,所以我们套个while循环,就能循环输入了:


int main()
{while (1){// 1、输出提示符printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());// 2、获取用户输入的命令char commandline[SIZE];Interactive(commandline, SIZE);printf("test:%s\n", commandline);// 3、对命令行字符串进行切割Split(commandline);// 4、执行分割好的命令Execute();}return 0;
}

六、发现cd命令用不了(内建命令)

当我们使用cd命令时,发现没有起作用,比如cd -,没有返回上一次的工作目录:

原因在于:

有些命令不应该让子进程去执行的,而是应该由shell自己去执行,就不如上述的cd命令,这种命令叫内建命令

所以我们在执行命令之前应该要先处理内建命令

七、处理内建命令cd:

char* Home()
{return getenv("HOME");
}int BuildinCmd()
{int ret = 0;//检查是否为内建命令,是 1,否 0if(strcmp("cd",argv[0]) == 0){//执行ret = 1;char* target = argv[1];if(!target) target = Home();//如果只输入cd,则argv[1]的值为0,则会进入if语句,默认跳转到Home()工作目录//通过系统调用chdir,改变当前工作目录chdir(target);//虽然具体的工作目录变了,但是命令行提示符中工作目录我们没有实时更新,所以还没有变//此时需要处理一下,修改PWD环境变量,这样下次循环时,命令行提示符获取的就是当前路径。snprintf(pwd,SIZE,"PWD=%s",target);putenv(pwd);}return ret;
}int main()
{while (1){// 1、输出提示符printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());// 2、获取用户输入的命令char commandline[SIZE];Interactive(commandline, SIZE);// 3、对命令行字符串进行切割Split(commandline);// 4、处理内建命令int n = BuildinCmd();if(n)continue;// 5、执行分割好的命令Execute();}return 0;
}

八、存在一个小问题:

问题如下图:

该现象的原因在于,用户输入指令cd ..后target字符串的内容就变成了"..",后续调用chdir,因为chdir是系统调用,内部是处理了"."和".."的,所以这里会正常执行,但后面调用snprintf函数时,pwd的值就变成了"..",这样putenv改变的环境变量的内容就变成了"..",下次循环命令行提示的地方读取到的环境变量值就为".."。

因为在这之前,我们已经用chdir函数改变了当前工作目录了,所以我们后面使用一个接口叫:getcwd(),该接口返回的就是当前工作目录,用该接口的返回传给getenv,这样环境变量就能正常修改了

int BuildinCmd()
{int ret = 0;//检查是否为内建命令,是 1,否 0if(strcmp("cd",argv[0]) == 0){//执行ret = 1;char* target = argv[1];if(!target) target = Home();//如果只输入cd,则argv[1]的值为0,则会进入if语句,默认跳转到Home()工作目录//通过系统调用chdir,改变当前工作目录chdir(target);char temp[1024];getcwd(temp,1024);//虽然具体的工作目录变了,但是命令行提示符中工作目录我们没有实时更新,所以还没有变//此时需要处理一下,修改PWD环境变量,这样下次循环时,命令行提示符获取的就是当前路径。snprintf(pwd,SIZE,"PWD=%s",temp);putenv(pwd);}return ret;
}

八、处理内建命令export

export是用来导入新的环境变量的,也是一个内建命令,因为只有将新环境变量导入给自己,这样才能被子进程继承下去。

直接else if 接着判断即可:

九、获取最近一次进程的退出码

十、处理内建命令echo

 else if(strcmp("echo",argv[0]) == 0){ret = 1;if(argv[1] == NULL){printf("\n");}else{if(argv[1][0] == '$')//$用于查看环境变量的值{if(argv[1][1] == '?')//$?:查看进程退出码{printf("%d\n",lastcode);lastcode = 0;}else{char* e = getenv(argv[1]+1);//echo $PWDif(e) printf("%s\n",e);}}else{//如果不是以$开头,则正常打印内容printf("%s\n",argv[1]);}}}

十一、让ls指令输出的内容带上颜色

十二、完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define SIZE 1024
#define MAX_ARGC 64
#define SEP " "// 全局进程
char *argv[MAX_ARGC];
//工作目录
char pwd[SIZE];
//环境变量
char env[SIZE];
//进程退出信息
int lastcode = 0;// 获取主机名
const char *HostName()
{char *hostname = getenv("HOSTNAME");if (hostname)return hostname;elsereturn "None";
}// 获取当前登录的用户名
const char *UserName()
{char *username = getenv("USER");if (username)return username;elsereturn "None";
}// 获取当前工作目录
const char *CurrentWorkDir()
{char *currentworkdir = getenv("PWD");if (currentworkdir)return currentworkdir;elsereturn "None";
}// 获取用户输入的命令
void Interactive(char out[], int size)
{fgets(out, SIZE, stdin);     // stdin是标准输入流,意思就是从键盘获取数据保存到commandline中out[strlen(out) - 1] = '\0'; // 因为fgets会读取换行符,所以这步我们去掉换行。
}// 对字符串进行分割
void Split(char in[])
{int i = 0;argv[i++] = strtok(in, SEP); // 对字符串commandline以空格作为分隔符进行切割,"ls -a -l"while (argv[i++] = strtok(NULL, SEP)); // 进行第二次切割时,strtok第一个参数需要传入NULL。并且最后会填入NULLif(strcmp(argv[0], "ls") == 0){argv[i - 1] = "--color";//即在字符串末尾加上--color选项argv[i] = NULL;}
}void Execute()
{// 因为程序替换后,不会在执行之后的代码,所以这里创建子进程去执行最合适pid_t id = fork();if (id == 0){// 子进程通过程序替换执行命令execvp(argv[0], argv);exit(1);}// 父进程进行等待,并查看退出信息int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid == id){//使用宏解析出退出码lastcode = WEXITSTATUS(status);}// printf("run done,rid: %d\n", rid);
}char* Home()
{return getenv("HOME");
}int BuildinCmd()
{int ret = 0;//检查是否为内建命令,是 1,否 0if(strcmp("cd",argv[0]) == 0){//执行ret = 1;char* target = argv[1];if(!target) target = Home();//如果只输入cd,则argv[1]的值为0,则会进入if语句,默认跳转到Home()工作目录//通过系统调用chdir,改变当前工作目录chdir(target);char temp[1024];getcwd(temp,1024);//虽然具体的工作目录变了,但是命令行提示符中工作目录我们没有实时更新,所以还没有变//此时需要处理一下,修改PWD环境变量,这样下次循环时,命令行提示符获取的就是当前路径。snprintf(pwd,SIZE,"PWD=%s",temp);putenv(pwd);}else if(strcmp("export",argv[0]) == 0){ret = 1;if(argv[1]){strcpy(env,argv[1]);putenv(env);}}else if(strcmp("echo",argv[0]) == 0){ret = 1;if(argv[1] == NULL){printf("\n");}else{if(argv[1][0] == '$')//$用于查看环境变量的值{if(argv[1][1] == '?')//$?:查看进程退出码{printf("%d\n",lastcode);lastcode = 0;}else{char* e = getenv(argv[1]+1);//echo $PWDif(e) printf("%s\n",e);}}else{//如果不是以$开头,则正常打印内容printf("%s\n",argv[1]);}}}return ret;
}int main()
{while (1){// 1、输出提示符printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());// 2、获取用户输入的命令char commandline[SIZE];Interactive(commandline, SIZE);// 3、对命令行字符串进行切割Split(commandline);// 4、处理内建命令int n = BuildinCmd();if(n)continue;// 5、执行分割好的命令Execute();}return 0;
}

http://www.dtcms.com/a/500999.html

相关文章:

  • 销售网站设计wordpress修改wpadmin
  • 机器学习(3)梯度下降
  • 深圳知名网站设计公司排名企业网站源码变现方法
  • 基于springboot的美食城服务管理系统
  • 公司网站维护与更新外贸搜索引擎
  • 国庆爆火的Sora2使用初探和实例生成
  • 迪拜哪个网站是做网站的河北邢台贴吧
  • 【与C++的邂逅】--- 继承和多态扩展
  • 做网站现在用什么语言jsp怎么做网站
  • 有什么网站可以下做闭软件大气科技类企业公司网站源码
  • Render Scale Scaling Up and Down
  • 挂别人公司做网站可以吗wordpress 高级选项
  • 网站百度快照更新高校资源网网站建设方案
  • LangGraph学习笔记(五):langgraph多轮对话下的短期记忆
  • DVWA靶场(Damn Vulnerable Web Application)
  • 可执行程序启动优化与依赖隔离案例(通过 dlopen 插件化)
  • 宁波建设银行网站首页网站建设硬件和软件技术环境配置
  • 基础的IO
  • 网站结构优化建议政务服务网站建设运行情况
  • 住建部建设厅官方网站中国空间站组合体
  • asp.net mvc 网站开发之美网站建设解决方案好处
  • 百度云服务器搭建网站步骤百度怎么做网站广告
  • USART--串口
  • 天津做网站哪个公司好上海搬家公司收费
  • vs做网站链接sql创建一个网站的最常用的方法是先建立一个文件夹
  • C++:从0开始学习链表
  • TPFanCtrl2,一款ThinkPad风扇控制工具
  • 辽宁地矿建设集团有限公司网站办办网官网
  • 网站建设协议书 印花税阿里巴巴网站域名注册
  • Redis的过期策略与内存淘汰机制