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

成都网站推广如何邵阳网

成都网站推广如何,邵阳网,熊猫网站ppt,腾讯企业邮箱域名可以做网站吗文章目录 一、shell的实现细节1.shell的一些细节2.用户名、主机名、工作目录2.输入命令3.改为循环4.切割字符串5.普通命令的执行6.内建命令的处理7.子进程的退出码8.总结 二、模式实现shell完整代码 一、shell的实现细节 1.shell的一些细节 shell操作系统的一个外壳程序。 s… 文章目录 一、shell的实现细节1.shell的一些细节2.用户名、主机名、工作目录2.输入命令3.改为循环4.切割字符串5.普通命令的执行6.内建命令的处理7.子进程的退出码8.总结 二、模式实现shell完整代码 一、shell的实现细节 1.shell的一些细节 shell操作系统的一个外壳程序。 shell/bash也是一个进程执行指令的时候本质就是自己创建子进程执行的 2.用户名、主机名、工作目录 当我们进入shell的时候我们知道会出现一个这样的东西 我们先来实现一下它 其实关于这些信息在我们的环境变量里面刚好就有 所以这里我们就不用系统调用了而是通过环境变量来完成 #includestdio.h #includestdlib.h#define LEFT [ #define RIGHT ] #define LABLE #const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); } int main() {printf(LEFT%s%s %sRIGHT LABLE\n,getusername(),gethostname(),getpwd());return 0; }如上代码所示我们现在就可以简单的实现打开shell时候要输入命令行的界面 运行结果为 不过由于我们后序要输入一个命令由于输入结束后本身带有换行所以我们这里可以去掉这个换行 2.输入命令 我们可以先直接加上一个scanf,这样的话它就会去接收命令了 但是这样对吗我们可以加上一个打印来看看结果 运行结果如下我们可以看到其实打印结果并非我们的预期 这其实是因为scanf它本身读取到空格就结束了所以我们需要一次读取一行 在c语言中有一个函数叫做fgets char *fgets(char *s, int size, FILE *stream);这个函数的意思是从stream这个流中读取size个字符放入s中。s是放在哪里size是可以访问多少 如下所示在这里我们需要注意的是这里对于27行我们可以不用对这个大小减一。都是可以的 运行结果为 那么在这里我们有一个问题这里的s有可能为空吗即有可能输入失败吗 在不考虑设备出现问题的情况下其实是不可能的即便我们什么都不输入它也会由于我们按了\n而将这个字符给输入进去。 而且我们发现我们在打印的时候多了一个空行这个空行其实就是因为我们输入了这个\n字符所导致的所以我们可以进行一次调整 #includestdio.h #includestdlib.h #includeassert.h #includestring.h#define LEFT [ #define RIGHT ] #define LABLE ##define LINE_SIZE 1024 char commandline[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); } int main() {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(commandline,sizeof(commandline),stdin);assert(s);commandline[strlen(commandline) - 1] \0;if(s)printf(echo : %s,commandline);return 0; }运行结果为 为了方便我们可以将对应的代码给写为一个函数 #includestdio.h #includestdlib.h #includeassert.h #includestring.h#define LEFT [ #define RIGHT ] #define LABLE ##define LINE_SIZE 1024 char commandline[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); }void Interact(char* cline,int size) {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int main() {Interact(commandline,sizeof(commandline));printf(echo : %s,commandline);return 0; }然后运行结果为 3.改为循环 我们的前面的代码还有的缺陷就是只能用一次所以我们不妨直接将其改为一个循环结构 #includestdio.h #includestdlib.h #includeassert.h #includestring.h#define LEFT [ #define RIGHT ] #define LABLE ##define LINE_SIZE 1024 char commandline[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); }void Interact(char* cline,int size) {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int main() {int quit 0;while(!quit){Interact(commandline,sizeof(commandline));printf(echo : %s\n,commandline);}return 0; }这样的话看起来就已经像回事了 4.切割字符串 为了分析这个指令我们首先要做的就是先将字符串给切割出来。放到一个数组里面去 于是我们可以利用这个函数 char *strtok(char *str, const char *delim);第一个参数是待分割的字符串第二个参数是分割的字符 这个函数每调用一次便会截取一次字符串。具体操作方法可见下文 字符串函数详解 最终代码如下所示 #includestdio.h #includestdlib.h #includeassert.h #includestring.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32char commandline[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); }void Interact(char* cline,int size) {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char* argv[]) {int i 0;argv[i] strtok(commandline,DELIM);while(argv[i] strtok(NULL,DELIM));return i - 1; } int main() {char* argv[ARGC_SIZE] {NULL};int quit 0;while(!quit){Interact(commandline,sizeof(commandline));int argc splitstring(argv);if(argc 0) continue;//测试分割for(int i 0; argv[i]; i){printf([%d] : %s\n,i,argv[i]);}}return 0; }运行结果为 5.普通命令的执行 由于我们的命令分为内建命令和普通命令。这里我们先考虑普通命令 对于普通命令我们的基本思路是创建一个子进程然后通过程序替换来实现。 这里的程序替换根据我们已有的条件最好选择时候execvp/execvpe。环境变量可带可不带但是v和p一定要带上因为我们需要从PATH环境变量中去找指令且我们已经有了一个数组了所以使用v形式更加方便 如下所示我们就可以实现一个简单的普通命令的执行了 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); }void Interact(char* cline,int size) {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char* argv[]) {int i 0;argv[i] strtok(commandline,DELIM);while(argv[i] strtok(NULL,DELIM));return i - 1; } int main() {extern char** environ;char* argv[ARGC_SIZE] {NULL};int quit 0;while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(argv);if(argc 0) continue;// for(int i 0; argv[i]; i)// {// printf([%d] : %s\n,i,argv[i]);// }//4.指令的判断(内建命令和普通命令)//5.普通命令的执行pid_t id fork();if(id 0){perror(fork);}else if (id 0){//子进程执行命令execvpe(argv[0],argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){}}}return 0; } 我们可以简单的使用一下 我们发现这些命令都可以正常的使用。 不过相比原本的shell还是有一些区别的比如说我们的shell中像目录文件可执行程序没有颜色。ll指令还没有办法解析因为没有支持改名等问题。 而且还有当我们想要使用内建命令的时候是没有任何效果的 因为这是子进程在跑这个命令最后变化的都是子进程的目录等最后子进程退出了。所以最终就没有任何变化。 我们现在可以将普通指令的执行给封装为一个函数如下所示 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE]; char* argv[ARGC_SIZE] {NULL}; extern char** environ; int last_code 0; int quit 0;const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } const char* getpwd() {return getenv(PWD); }void Interact(char* cline,int size) {printf(LEFT%s%s %sRIGHT LABLE ,getusername(),gethostname(),getpwd());char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char cline[],char* _argv[]) {int i 0;_argv[i] strtok(cline,DELIM);while(_argv[i] strtok(NULL,DELIM));return i - 1; }void NormalExcute(char* _argv[]) {pid_t id fork();if(id 0){perror(fork);return;}else if (id 0){//子进程执行命令execvpe(_argv[0],_argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){last_code WEXITSTATUS(status);}} } int main() {while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(commandline,argv);if(argc 0) continue;//4.指令的判断(内建命令和普通命令)//5.普通命令的执行NormalExcute(argv);}return 0; }6.内建命令的处理 对于内建命令我们则是直接判断即可 比如下面 运行结果最终为我们可以发现确实更改当前目录了 不过我们会发现这个前面字符串的显示还是存在一些问题的 这是因为我们当前所使用的是环境变量的方式我们可以去sprintf函数去修改环境变量。不过这样有很多比较麻烦的事情 最简单的方式是我们不用环境变量来获取当前工作目录了我们可以直接用getcwd这个函数来使用它可以获得当前的工作目录。放入一个数组中。 如下代码所示完成了cd的内建命令并且我们实现了ls在显示时候的颜色输出。 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE]; char* argv[ARGC_SIZE] {NULL}; extern char** environ; int last_code 0; int quit 0; char pwd[LINE_SIZE]; const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } void getpwd() {getcwd(pwd,sizeof(pwd)); }void Interact(char* cline,int size) {getpwd();printf(LEFT%s%s %sRIGHTLABLE ,getusername(),gethostname(),pwd);char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char cline[],char* _argv[]) {if(strcmp(cline,) 0) return 0;int i 0;_argv[i] strtok(cline,DELIM);while(_argv[i] strtok(NULL,DELIM));return i - 1; }void NormalExcute(char* _argv[]) {pid_t id fork();if(id 0){perror(fork);return;}else if (id 0){//子进程执行命令execvpe(_argv[0],_argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){last_code WEXITSTATUS(status);}} } int BuildCommand(char* _argv[],int _argc) {if(_argc 2 strcmp(_argv[0],cd) 0){chdir(_argv[1]);getpwd();sprintf(getenv(PWD),%s,pwd);return 1;}if(_argc 0 strcmp(_argv[0],ls) 0){_argv[_argc] --color;_argv[_argc] NULL;}return 0; } int main() {while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(commandline,argv);if(argc 0) continue; //4.指令的判断(内建命令和普通命令)int n BuildCommand(argv,argc);//5.普通命令的执行if(!n) NormalExcute(argv);}return 0; }我们再来实现一下其他的内建命令比如echo命令如果我们直接使用的话相当于是调用了子进程中的echo命令它会出现这样的问题无论我们输入什么最终也依然输出什么 而且如果我们导入环境变量的时候直接使用export也是不可以的 因为这是创建了子进程才导入的我们不希望创建子进程所以就需要内建命令 直接在这里putenv即可 这样的话就有了这个环境变量了 不过上面的其实还存在很多问题 因为如果我们再次使用一下export的话我们会发现原来加入的环境变量消失了 这其实是因为我们前面的代码是将_argv中的内容直接导入到了环境变量中。这里的导入不是说拷贝一份。而是将这个地址写入到了环境变量所对应的空间中。而我们后面再次导入的时候已经将这块的内容修改了。所以说原来的就不见了。总之环境变量表保存的不是字符串而是地址。 所以我们需要专门开辟一块空间用来存储环境变量 然后我们最后将echo给实现一下即可。 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE]; char* argv[ARGC_SIZE] {NULL}; extern char** environ; int last_code 0; int quit 0; char pwd[LINE_SIZE]; char myenv[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } void getpwd() {getcwd(pwd,sizeof(pwd)); }void Interact(char* cline,int size) {getpwd();printf(LEFT%s%s %sRIGHTLABLE ,getusername(),gethostname(),pwd);char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char cline[],char* _argv[]) {if(strcmp(cline,) 0) return 0;int i 0;_argv[i] strtok(cline,DELIM);while(_argv[i] strtok(NULL,DELIM));return i - 1; }void NormalExcute(char* _argv[]) {pid_t id fork();if(id 0){perror(fork);return;}else if (id 0){//子进程执行命令execvpe(_argv[0],_argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){last_code WEXITSTATUS(status);}} }int BuildCommand(char* _argv[],int _argc) {if(_argc 2 strcmp(_argv[0],cd) 0){chdir(_argv[1]);getpwd();sprintf(getenv(PWD),%s,pwd);return 1;}else if(_argc 2 strcmp(_argv[0],export) 0){strcpy(myenv,_argv[1]);putenv(myenv);return 1;}else if(_argc 2 strcmp(_argv[0],echo) 0){if(*_argv[1] $){char* val getenv(_argv[1] 1);if(val) printf(%s\n,val);}else {printf(%s\n,_argv[1]);}return 1;}if(_argc 0 strcmp(_argv[0],ls) 0){_argv[_argc] --color;_argv[_argc] NULL;}return 0; } int main() {while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(commandline,argv);if(argc 0) continue;//4.指令的判断(内建命令和普通命令)int n BuildCommand(argv,argc);//5.普通命令的执行if(!n) NormalExcute(argv);}return 0; } 7.子进程的退出码 当子进程退出的时候它会有一个退出码。 所以我们可以对于echo的内建命令在加上一个打印退出码的操作 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE]; char* argv[ARGC_SIZE] {NULL}; extern char** environ; int last_code 0; int quit 0; char pwd[LINE_SIZE]; char myenv[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } void getpwd() {getcwd(pwd,sizeof(pwd)); }void Interact(char* cline,int size) {getpwd();printf(LEFT%s%s %sRIGHTLABLE ,getusername(),gethostname(),pwd);char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char cline[],char* _argv[]) {if(strcmp(cline,) 0) return 0;int i 0;_argv[i] strtok(cline,DELIM);while(_argv[i] strtok(NULL,DELIM));return i - 1; }void NormalExcute(char* _argv[]) {pid_t id fork();if(id 0){perror(fork);return;}else if (id 0){//子进程执行命令execvpe(_argv[0],_argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){last_code WEXITSTATUS(status);}} }int BuildCommand(char* _argv[],int _argc) {if(_argc 2 strcmp(_argv[0],cd) 0){chdir(_argv[1]);getpwd();sprintf(getenv(PWD),%s,pwd);return 1;}else if(_argc 2 strcmp(_argv[0],export) 0){strcpy(myenv,_argv[1]);putenv(myenv);return 1;}else if(_argc 2 strcmp(_argv[0],echo) 0){if(strcmp(_argv[1],$?) 0){printf(%d\n,last_code);last_code 0;}else if(*_argv[1] $){char* val getenv(_argv[1] 1);if(val) printf(%s\n,val);}else {printf(%s\n,_argv[1]);}return 1;}if(_argc 0 strcmp(_argv[0],ls) 0){_argv[_argc] --color;_argv[_argc] NULL;}return 0; } int main() {while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(commandline,argv);if(argc 0) continue;//4.指令的判断(内建命令和普通命令)int n BuildCommand(argv,argc);//5.普通命令的执行if(!n) NormalExcute(argv);}return 0; } 运行效果如下 8.总结 所以当我们进行登录的时候系统就要启动一个shell进程那么我们shell本身的环境变量是从哪里来的 其实在我们用户的目录下就一个bash_profile文件 它里面的内容是这样的这里面就会帮助我们导入环境变量 类似的还有.bashrc文件等 所以说 当用户登录的时候shell会读取用户目录下的.bashprofile文件里面保存了导入环境变量的方式 二、模式实现shell完整代码 #includestdio.h #includestdlib.h #includeassert.h #includestring.h #includeunistd.h #includesys/types.h #includesys/wait.h#define LEFT [ #define RIGHT ] #define LABLE # #define DELIM \t #define LINE_SIZE 1024 #define ARGC_SIZE 32 #define EXIT_CODE 44char commandline[LINE_SIZE]; char* argv[ARGC_SIZE] {NULL}; extern char** environ; int last_code 0; int quit 0; char pwd[LINE_SIZE]; char myenv[LINE_SIZE];const char* getusername() {return getenv(USER); } const char* gethostname() {return getenv(HOSTNAME); } void getpwd() {getcwd(pwd,sizeof(pwd)); }void Interact(char* cline,int size) {getpwd();printf(LEFT%s%s %sRIGHTLABLE ,getusername(),gethostname(),pwd);char* s fgets(cline,size,stdin);(void)s;assert(s);commandline[strlen(cline) - 1] \0; } int splitstring(char cline[],char* _argv[]) {if(strcmp(cline,) 0) return 0;int i 0;_argv[i] strtok(cline,DELIM);while(_argv[i] strtok(NULL,DELIM));return i - 1; }void NormalExcute(char* _argv[]) {pid_t id fork();if(id 0){perror(fork);return;}else if (id 0){//子进程执行命令execvpe(_argv[0],_argv,environ);exit(EXIT_CODE);}else{int status 0;pid_t rid waitpid(id,status,0);if(rid id){last_code WEXITSTATUS(status);}} }int BuildCommand(char* _argv[],int _argc) {if(_argc 2 strcmp(_argv[0],cd) 0){chdir(_argv[1]);getpwd();sprintf(getenv(PWD),%s,pwd);return 1;}else if(_argc 2 strcmp(_argv[0],export) 0){strcpy(myenv,_argv[1]);putenv(myenv);return 1;}else if(_argc 2 strcmp(_argv[0],echo) 0){if(strcmp(_argv[1],$?) 0){printf(%d\n,last_code);last_code 0;}else if(*_argv[1] $){char* val getenv(_argv[1] 1);if(val) printf(%s\n,val);}else {printf(%s\n,_argv[1]);}return 1;}if(_argc 0 strcmp(_argv[0],ls) 0){_argv[_argc] --color;_argv[_argc] NULL;}return 0; } int main() {while(!quit){//2.交互问题解决命令行Interact(commandline,sizeof(commandline));//3.子串分割问题解析命令行int argc splitstring(commandline,argv);if(argc 0) continue;//4.指令的判断(内建命令和普通命令)int n BuildCommand(argv,argc);//5.普通命令的执行if(!n) NormalExcute(argv);}return 0; }
http://www.pierceye.com/news/293220/

相关文章:

  • 网站转备案申请学校网站建设申请书
  • 宜昌网站建设选择宜昌慧享互动线上店免费推广的软件
  • 网站建设主流语言织梦网站流动广告代码
  • 南京做网站公司哪个网站上做ppt比较好看的
  • 在服务器上搭建网站中国建设银行淮南分行网站
  • 网站建设什么服务器品牌哪个好南京企业制作网站
  • 太原有哪些做网站的公司如何伪原创 网站
  • 设计好的网站网站策划方案详解
  • 建网站潞城哪家强?企业网络推广技巧
  • 怎么建设网站让国外看wordpress 公司内网
  • 虚拟主机购买网站网站值不值得做seo
  • 长沙网站排名优化如何在网站做电子杂志
  • 石家庄科技网站在线解压zip网站
  • 不良网站举报中心官网做网站必须买云虚拟主机吗
  • 网站建设实习wordpress 登陆 插件下载
  • 做耳鼻喉医院网站多少钱北京网站建设营销
  • 济南网站建设就选搜点网络ok外贸平台补贴政策
  • 网站建设 学校百度快照优化培训班
  • 做阀门的英文网站怎么写西安seo服务公司排名
  • 淘宝客网站如何做推广古董手表网站
  • 网站虚拟主机查询企业文化建设的内容有哪些
  • 财经大学网站建设apicloud wordpress
  • 平面设计网站排行榜刚进外贸公司一个月多少钱
  • 企业网站最下面的那栏叫啥广州编程培训机构哪里好
  • 怎么学建设网站网站建设敬请期待图片素材
  • 滴滴出行的网站是哪家公司做的新媒体营销课程心得体会
  • 中国室内设计师联盟网站浙江手机版建站系统开发
  • 网站开源代码模版广州公司注册核名查询系统官网
  • 海外网站seo丹阳市住房建设管理局网站
  • 定制公司网站沙市做网站weisword