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

注册网站公司深圳装修公司报价

注册网站公司,深圳装修公司报价,搜狗站长工具,旅游网站设计接下来利用我们当前的知识#xff0c;撰写一个简单的shell外壳程序。 1.shell原理 shell的原理是实际上就是运行了一个父进程#xff0c;然后创建出子进程#xff0c;最后使用进程替换调用#xff0c;替换成其他程序。 2.shell实现 2.1.死循环 首先一个shell一旦运行起…接下来利用我们当前的知识撰写一个简单的shell外壳程序。 1.shell原理 shell的原理是实际上就是运行了一个父进程然后创建出子进程最后使用进程替换调用替换成其他程序。 2.shell实现 2.1.死循环 首先一个shell一旦运行起来就不会关闭除非关闭终端窗口因此一定是一个死循环。 int main() {while(1){//...}return 0 }2.2.提示字符串 运行一个shell有出现一个类似[usermyshell]$的输入提示符由于不能换行因此我们还需要使用fflush()进行刷新。 #include stdio.h int main() {while(1){printf([usermyshell]$ );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([usermyshell]$ );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([usermyshell]$ );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] --colorauto;//增加颜色参数让输出带有颜色}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([usermyshell]$ );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] --colorauto;//增加颜色参数让输出带有颜色}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] --colorauto;//增加颜色参数让输出带有颜色}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] --colorauto;//增加颜色参数让输出带有颜色}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] --colorauto;//增加颜色参数让输出带有颜色}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] --colorauto;//增加颜色参数让输出带有颜色}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] --colorauto;//增加颜色参数让输出带有颜色}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.zqtcl.cn/news/562204/

相关文章:

  • 一个大型网站建设得多少钱百度成都总部
  • 网站制作公司汉狮网络手机版网站优化
  • 铜川做网站logo 图标 设计
  • 如何做网站的注册页面南京宣传片公司有哪些
  • 中国建设机械教育协会网站网站建设中html中关于图片显示的标签有哪些
  • 网站过期后dede减肥网站源码
  • 营销型 手机网站网站建设方案后期服务
  • 怎么做一个个人网站建网站的八个步骤
  • 淘宝导购网站模版上海网站推广软件
  • 做影视网站引流湖北响应式网站建设费用
  • 网站统计cnzz网站空间有哪些
  • 泉州微信网站开发公司wordpress头像解决
  • 湛江网站建设皆选小罗24专业网站建设 福田
  • 厦门哪些做鲜花的网站门户网站开发设计报告
  • asp.net网站设计分工天津网站开发贴吧
  • 做多语言网站教程南宁vi设计公司
  • 百度联盟 网站备案wordpress 吾爱破解
  • 山西省建设厅网站首页网络营销推广为什么效果不好
  • 建材做网站好吗长沙做网站微联讯点不错
  • 建设小型网站分类门户网站系统
  • 文化馆网站数字化建设介绍138ip地址查询网站
  • 卖汽车的网站怎么做的建设服装网站的论文
  • 网络推广哪个网站好网站建设最低多少钱
  • 怎么在自己电脑做网站北京赛车网站开发
  • 门户网站内容wordpress上下页
  • 长安做英文网站营销型网站搭建
  • 网站开发交接清单seo排名优化方法
  • 各学院二级网站建设通报wordpress注册评论
  • 南通公司做网站无人在线完整免费高清观看
  • 廊坊网站推广局域网网站建设的步骤过程