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

wordpress会员注册怎样更改兰州做网站优化的公司

wordpress会员注册怎样更改,兰州做网站优化的公司,西安软件公司排名,虚拟商品自动发货网站搭建教程接下来利用我们当前的知识,撰写一个简单的shell外壳程序。 1.shell原理 shell的原理是实际上就是运行了一个父进程,然后创建出子进程,最后使用进程替换调用,替换成其他程序。 2.shell实现 2.1.死循环 首先一个shell一旦运行起…

接下来利用我们当前的知识,撰写一个简单的shell外壳程序。

1.shell原理

shell的原理是实际上就是运行了一个父进程,然后创建出子进程,最后使用进程替换调用,替换成其他程序。

2.shell实现

2.1.死循环

首先一个shell一旦运行起来就不会关闭(除非关闭终端窗口),因此一定是一个死循环。

int main()
{while(1){//...}return 0}

2.2.提示字符串

运行一个shell有出现一个类似[user@myshell]$的输入提示符,由于不能换行,因此我们还需要使用fflush()进行刷新。

#include <stdio.h>
int main()
{while(1){printf("[user@myshell]$ ");fflush(stdout);}return 0;
}

2.3.获取用户输入

#include <stdio.h>
#include <string.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串int main()
{while(1){//1.打印提示信息printf("[user@myshell]$ ");fflush(stdout);//2.获取 user 的输入memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串{//出错就直接跳出循环continue;}cmd_line[strlen(cmd_line) - 1] = '\0';//即使用户输入字符串超出范围,也能保证获取到一个完整的 C 风格字符串}return 0;
}

2.4.解析用户输入

#include <stdio.h>
#include <string.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符int main()
{while(1){//1.打印提示信息printf("[user@myshell]$ ");fflush(stdout);//2.获取 user 的输入memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串{//出错就直接跳出循环continue;}cmd_line[strlen(cmd_line) - 1] = '\0';//即使用户输入字符串超出范围,也能保证获取到一个完整的 C 风格字符串//3.命令行字符解析//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL}return 0;
}

2.5.创建并且替换子进程

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符int main()
{while(1){//1.打印提示信息printf("[user@myshell]$ ");fflush(stdout);//2.获取 user 的输入memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串{//出错就直接跳出循环continue;}cmd_line[strlen(cmd_line) - 1] = '\0';//即使用户输入字符串超出范围,也能保证获取到一个完整的 C 风格字符串//3.命令行字符解析//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL//4.fork() 创建子进程,execvp() 替换子进程pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}return 0;
}

2.6.debug

有一个小小的bug我们没有解决,就是使用cd命令的时候,没有办法切入到对应的目录,这是为什么呢?

3.shell拓展

3.1.用户名、主机名、目录获取

上面我们只是生硬显示了user充当用户名字,实际上我们可以通过环境变量获取执行shell的用户的名字,还可以获取在不同环境下的系统主机名字,使用这两个环境变量的内容填充到提示字符串中,目录也可以这样操作。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符const char* GetUserName()//获取用户名字
{const char* userName = getenv("USER");if(userName) return userName;elsereturn "none";
}const char* GetHostName()//获取主机名字
{const char* hostName = getenv("HOSTNAME");if(hostName)return hostName;elsereturn "none";
}const char* GetPwd()//获取路径地址
{const char* pwd = getenv("PWD");if(pwd)return pwd;elsereturn "none";
}int main()
{while(1){//1.打印提示信息printf("[%s@%s %s]$ ", GetUserName(), GetHostName(), GetPwd());fflush(stdout);//2.获取 user 的输入memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串,不能使用 scanf(){//出错就直接跳出循环continue;}cmd_line[strlen(cmd_line) - 1] = '\0';//将用户输入的字符串去掉 \n//3.命令行字符解析//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL//4.fork() 创建子进程,execvp() 替换子进程pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}return 0;
}

3.2.封装步骤

既然上面的用户名、主机名、路径都进行了函数封装,那么我也可以选择将部分的代码进行分钟,变得更有逻辑。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符const char* GetUserName(void)//获取用户名字
{const char* userName = getenv("USER");if(userName) return userName;elsereturn "none";
}const char* GetHostName(void)//获取主机名字
{const char* hostName = getenv("HOSTNAME");if(hostName)return hostName;elsereturn "none";
}const char* GetPwd(void)//获取路径地址
{const char* pwd = getenv("PWD");if(pwd)return pwd;elsereturn "none";
}void Print(void)
{printf("[%s@%s %s]$ ", GetUserName(), GetHostName(), GetPwd());fflush(stdout);
}bool GetUserCommand()
{memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串,不能使用 scanf(){//出错就直接跳出循环return false;}cmd_line[strlen(cmd_line) - 1] = '\0';//将用户输入的字符串去掉 \nreturn true;
}void AnalyzeStr(void)
{//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;//处理特殊的命令情况if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL
}void RunCommand(void)
{pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}else{//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}
}int main()
{while(1){//1.打印提示信息Print();//2.获取 user 的输入if(!GetUserCommand())continue;//3.命令行字符解析AnalyzeStr();//4.fork() 创建子进程,execvp() 替换子进程RunCommand();}return 0;
}

3.3.debug

如果使用了上面的shell程序,很快就会发现两个bug

3.3.1.无法直接输入换行

在系统默认运行的shell中,允许用户不断回车,而我们的程序如果直接回车就会退出,这个问题的解决思路很简单,只需要在获取字符的时候,查看用户输入的字符长度是否为0即可,若是就让GetUserCommand()返回false,执行continue语句即可。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符const char* GetUserName(void)//获取用户名字
{const char* userName = getenv("USER");if(userName) return userName;elsereturn "none";
}const char* GetHostName(void)//获取主机名字
{const char* hostName = getenv("HOSTNAME");if(hostName)return hostName;elsereturn "none";
}const char* GetPwd(void)//获取路径地址
{const char* pwd = getenv("PWD");if(pwd)return pwd;elsereturn "none";
}void Print(void)
{printf("[%s@%s %s]$ ", GetUserName(), GetHostName(), GetPwd());fflush(stdout);
}bool GetUserCommand()
{memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串,不能使用 scanf(){//出错就直接跳出循环return false;}cmd_line[strlen(cmd_line) - 1] = '\0';//将用户输入的字符串去掉 \nif(strlen(cmd_line) == 0)return false;return true;
}void AnalyzeStr(void)
{//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;//处理特殊的命令情况if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL
}
void RunCommand(void)
{pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}else{//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}
}int main()
{while(1){//1.打印提示信息Print();//2.获取 user 的输入if(!GetUserCommand())continue;//3.命令行字符解析AnalyzeStr();//4.fork() 创建子进程,execvp() 替换子进程RunCommand();}return 0;
}

3.3.2.无法切换对应目录

还可以发现一个比较严重的问题,我们无法使用cd命令切换目录,这是为什么呢?原因也很简单,cd程序替换的是子进程,该目录只让子进程进行了切换命令,而我们希望的是父进程自己执行cd,修改父进程的工作路径。因此,我们需要调用一些库函数,更改父进程的工作环境。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符const char* GetUserName(void)//获取用户名字
{const char* userName = getenv("USER");if(userName) return userName;elsereturn "none";
}const char* GetHostName(void)//获取主机名字
{const char* hostName = getenv("HOSTNAME");if(hostName)return hostName;elsereturn "none";
}const char* GetPwd(void)//获取路径地址
{const char* pwd = getenv("PWD");if(pwd)return pwd;elsereturn "none";
}void Print(void)//打印提示字符
{printf("[%s@%s %s]$ ", GetUserName(), GetHostName(), GetPwd());fflush(stdout);
}bool GetUserCommand(void)//获取用户命令字符串
{memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串,不能使用 scanf(){//出错就直接跳出循环return false;}cmd_line[strlen(cmd_line) - 1] = '\0';//将用户输入的字符串去掉 \nif(strlen(cmd_line) == 0)return false;return true;
}void AnalyzeStr(void)//拆分解析用户字符串
{//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;//处理特殊的命令情况if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL
}bool DoBuildin(void)//判断是否内建命令并且执行
{//内建命令if(strcmp(g_argv[0], "cd") == 0)       {   printf("父进程 run:\n");//更改路径的命令char* path = NULL;if(g_argv[1] == NULL){path = ".";}else{path = g_argv[1];}chdir(path);return true;}return false;
}void RunCommand(void)//运行用户命令
{pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}else{//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}
}int main()
{while(1){//1.打印提示信息Print();//2.获取 user 的输入if(!GetUserCommand())continue;//3.命令行字符解析AnalyzeStr();//4.处理内建命令if(DoBuildin())continue;//5.fork() 创建子进程,execvp() 替换子进程RunCommand();}return 0;
}

这种只能由父进程来执行的命令也叫做“内建命令”,这类环境变量有很多。

3.3.3.无法更改环境变量

还有一个比较尴尬的问题,我们发现使用cd指令后,提示字符串的地址无法及时更新,也就是没有更新对应的环境变量。如果更新呢?可以使用系统提供的接口getcwd()来获取调用该接口进程所在的路径。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h> 
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>#define NUM 1024
char cmd_line[NUM];//保存完整命令字符串#define SIZE 32
char* g_argv[SIZE];//保存打散后的命令字符串,是一个数组#define SEP " "//分隔符char cwd[1024];//环境变量const char* GetUserName(void)//获取用户名字
{const char* userName = getenv("USER");if(userName) return userName;elsereturn "none";
}const char* GetHostName(void)//获取主机名字
{const char* hostName = getenv("HOSTNAME");if(hostName)return hostName;elsereturn "none";
}const char* GetPwd(void)//获取路径地址
{const char* pwd = getenv("PWD");if(pwd)return pwd;elsereturn "none";
}void Print(void)
{printf("[%s@%s %s]$ ", GetUserName(), GetHostName(), GetPwd());fflush(stdout);
}bool GetUserCommand()
{memset(cmd_line, '\0', sizeof(cmd_line));//设定初始值if(fgets(cmd_line, sizeof(cmd_line), stdin) == NULL)//获取字符串,不能使用 scanf(){//出错就直接跳出循环return false;}cmd_line[strlen(cmd_line) - 1] = '\0';//将用户输入的字符串去掉 \nif(strlen(cmd_line) == 0)return false;return true;
}void AnalyzeStr(void)
{//虽然可以自己写一个算法解析,但是我们可以使用一些现有的接口g_argv[0] = strtok(cmd_line, SEP);//第一次调用需要传入原始字符串和分隔符int index = 1;//处理特殊的命令情况if(strcmp(g_argv[0], "ls") == 0)//如果输入的命令是 ls 就进行一些特殊处理{g_argv[index++] = "--color=auto";//增加颜色参数,让输出带有颜色}while(g_argv[index++] = strtok(NULL, SEP));//第二次还想要解析原始字符串,就需要传入 NULL
}bool DoBuildin()
{//内建命令if(strcmp(g_argv[0], "cd") == 0)       {   printf("父进程 run:\n");//更改路径的命令char* path = NULL;if(g_argv[1] == NULL){path = ".";}else{path = g_argv[1];}chdir(path);char tmp[1024];getcwd(tmp, sizeof(tmp));//获取当前进程所在的地址(工作目录)sprintf(cwd, "PWD=%s", tmp);//组合环境变量putenv(cwd);//设置环境变量return true;}return false;
}void RunCommand(void)
{pid_t id = fork();if(id == 0)//child{printf("子进程 run:\n");execvp(g_argv[0], g_argv);//自动在环境变量中搜索 g_argv[0] 的文件,执行 g_argv 数组存储的指令exit(1);//没替换成功就会异常退出}else{//fatherint status;pid_t ret = waitpid(id, &status, 0);//阻塞等待if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));}
}int main()
{while(1){//1.打印提示信息Print();//2.获取 user 的输入if(!GetUserCommand())continue;//3.命令行字符解析AnalyzeStr();//4.处理内建命令if(DoBuildin())continue;//5.fork() 创建子进程,execvp() 替换子进程RunCommand();}return 0;
}
http://www.yayakq.cn/news/64316/

相关文章:

  • 广州网站推广多少钱餐饮网络营销方式
  • 网站做a视频在线观看网站长沙网站定制开发建设
  • 有没有网站建设的教程哪里可以下载免费的个人简历模板
  • 打折网站模板网站制作+app+公众号
  • 营口市城乡住房建设局网站网络广告策划书范文
  • 在建设局网站上怎么样总监解锁制作个人主页
  • 网站后台建设教程做任务领礼品的网站
  • 建设工程有限公司企业网站定制网站需要多少钱
  • 阿里云做网站视频无法播放wordpress列类型
  • 电商网站优化方案宜兴做网站多少钱
  • 苏州建设局统计网站吉林省建设信息网电话
  • 做网站教程pdf站酷做网站
  • 湖南网站建设kaodezhu友情链接网站被降权
  • 厦门网站建设维护各省施工备案网站
  • 企业网站建设需要哪些设备wordpress如何编辑
  • 十堰企业网站制作公司网页设计模板套用步骤
  • 贵州国高建设工程有限公司 网站高端网线
  • 织梦网站调整微信嵌入网站开发
  • 网站建设 技术 哪些广东外贸网站定制
  • 网站开发包括哪些技术comment_form wordpress
  • 网站如何设计方案广西建设厅网站资质查询
  • 龙华网站建设价格生成二维码在线生成器
  • 智能网站建设制作微信公众号怎么二次开发
  • 中国建设银行公积金网缴网站肥西县市建设局网站
  • 大型网站制作都有哪些网站建设的技术目标
  • 淮安做网站就找卓越凯欣电邮注册网站
  • 兰州企业网站优化深圳企业网站制作公司哪家好
  • php网站多语言翻译怎么做福州建站服务
  • 外包兼职做图的网站app开发网站模板
  • 做网站属于什么技术wordpress如何添加首页