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

项目《基于Linux下的mybash命令解释器》(二)

一、使用系统命令的完整代码

#include<stdio.h>
#include<wait.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<pwd.h>#define ARG_MAX 10//防止参数不够,可以做到一改全改char *get_cmd(char *buff,char *myargv[]){//这个函数的作用是分割命令if(buff == NULL||myargv == NULL){return NULL;//说明用户没有输入命令}char *s = strtok(buff," ");//第一次调用strtokint i = 0;while(s!=NULL){//不确定用户输入的命令需要分割几次,只要分割到字符串末尾为'\0',就会结束myargv[i++] = s;//保存分割的结果s = strtok(NULL," ");//后续调用不用再传buff,因为内部有指针会记录}return myargv[0];
}void run_cmd(char *path,char *myargv[]){//这个函数的作用是当输入命令为普通命令时,创建子进程执行if(path == NULL || myargv == NULL)return;pid_t pid = fork();if(pid == -1)return;//下面我们要让父子进程做不一样的事情if(pid == 0)//子进程进入if{execvp(path,myargv);//这里选择替换系列时,选带v,这样就可以传数组,选带p的,这样就不需要传环境变量perror("execvp error!\n");//一定要记得打印错误信息,这样方便我们明确的知道execvp是否执行成功// exit(0);}else//父进程进入esle{//这里要记得处理将死进程wait(NULL);}
}void printf_info(){//打印提示信息,获取用户名,主机名,当前位置,获取用户角色(普通用户还是管理员)char *user_str="$";//默认为普通用户int user_id = getuid();if(user_id == 0){//当uid=0时为root,将$改为#user_str = "#";}struct passwd * ptr = getpwuid(user_id);//得到用户名if(ptr == NULL)//如果为NULL,也就是出现问题了,那么打印bash的版本号{printf("mybash1.0>> ");fflush(stdout);return;}//获取主机名char hostname[128] = {0};if(gethostname(hostname,128)==-1){//如果获取主机名失败,打印版本号printf("mybash1.0>> ");fflush(stdout);return;}//获取主机路径char dir[256] = {0};if(getcwd(dir,256)==NULL){//如果获取路径失败,打印版本号printf("mybash1.0>> ");fflush(stdout);return;}printf("\033[1;32m%s@%s\033[0m  \033[1;34m%s\033[0m%s ",ptr->pw_name,hostname,dir,user_str);fflush(stdout);
}int main()
{while(1){printf_info();char buff[128]={0};fgets(buff,128,stdin);buff[strlen(buff)-1] = '\0';//去除buff里面的\n,防止exit和exit\n不匹配char *myargv[ARG_MAX] = {0};char *cmd = get_cmd(buff,myargv);//提取buff里面的命令if(cmd == NULL){continue;}else if(strcmp(cmd,"cd")==0){if(myargv[1] != NULL){//当cd后面有路径时if(chdir(myargv[1])==-1){perror("cd err!\n");}}//当用户只输入cd时,会进入家目录(和系统保持一致)}else if(strcmp(cmd,"exit")==0){break;//若为exit,则退出内部exit(0);//可以,但不好}else{//普通命令//fork + execrun_cmd(cmd,myargv);//也可以直接传myargv}}exit(0);
}

二、使用自己环境变量的完整代码

//mybash.c
#include<stdio.h>
#include<wait.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<pwd.h>#define ARG_MAX 10//防止参数不够,可以做到一改全改
#define PATH_BIN "/home/stu/quzijie/class03/test15/mybin/"char *get_cmd(char *buff,char *myargv[]){//这个函数的作用是分割命令if(buff == NULL||myargv == NULL){return NULL;//说明用户没有输入命令}char *s = strtok(buff," ");//第一次调用strtokint i = 0;while(s!=NULL){//不确定用户输入的命令需要分割几次,只要分割到字符串末尾为'\0',就>会结束myargv[i++] = s;//保存分割的结果s = strtok(NULL," ");//后续调用不用再传buff,因为内部有指针会记录}return myargv[0];
}void run_cmd(char *path,char *myargv[]){//这个函数的作用是当输入命令为普通命令时,创>建子进程执行if(path == NULL || myargv == NULL)return;pid_t pid = fork();if(pid == -1)return;//下面我们要让父子进程做不一样的事情if(pid == 0)//子进程进入if{//使用自己的环境变量mybin//在只输入命令的情况下拼接,./和/完整路径这两种情况都不需要拼接char pathname[128] = {0};if(strncmp(path,"/",1)==0||strncmp(path,"./",2)==0)//不拼接{strcpy(pathname,path);}else//拼接,只有命令{strcpy(pathname,PATH_BIN);//先复制路径strcat(pathname,path);//然后和命令拼接}execv(pathname,myargv);perror("execv error!\n");exit(0);}else//父进程进入esle{//这里要记得处理将死进程wait(NULL);}
}
void printf_info(){//打印提示信息,获取用户名,主机名,当前位置,获取用户角色(普通用
户还是管理员)char *user_str="$";//默认为普通用户int user_id = getuid();if(user_id == 0){//当uid=0时为root,将$改为#user_str = "#";}struct passwd * ptr = getpwuid(user_id);//得到用户名if(ptr == NULL)//如果为NULL,也就是出现问题了,那么打印bash的版本号{printf("mybash1.0>> ");fflush(stdout);return;}//获取主机名char hostname[128] = {0};if(gethostname(hostname,128)==-1){//如果获取主机名失败,打印版本号printf("mybash1.0>> ");fflush(stdout);return;}//获取主机路径char dir[256] = {0};if(getcwd(dir,256)==NULL){//如果获取路径失败,打印版本号printf("mybash1.0>> ");fflush(stdout);return;}printf("\033[1;32m%s@%s\033[0m  \033[1;34m%s\033[0m%s ",ptr->pw_name,hostname,dir,user_str);fflush(stdout);
}
int main()
{while(1){printf_info();char buff[128]={0};fgets(buff,128,stdin);buff[strlen(buff)-1] = '\0';//去除buff里面的\n,防止exit和exit\n不匹配char *myargv[ARG_MAX] = {0};char *cmd = get_cmd(buff,myargv);//提取buff里面的命令if(cmd == NULL){continue;}else if(strcmp(cmd,"cd")==0){if(myargv[1] != NULL){//当cd后面有路径时if(chdir(myargv[1])==-1){perror("cd err!\n");}}//当用户只输入cd时,会进入家目录(和系统保持一致)}else if(strcmp(cmd,"exit")==0){break;//若为exit,则退出内部exit(0);//可以,但不好}else{//普通命令//fork + execrun_cmd(cmd,myargv);//也可以直接传myargv}}exit(0);
}
//mybin目录下的自己实现的命令
//clear.c
include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main(){printf("\033[2J\033[0;0H");
}
//pwd.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main(){char path[256] = {0};if(getcwd(path,256) == NULL) {   perror("getcwd error!\n");exit(1);}   printf("%s\n",path);exit(0);   
}
//ls.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
int main(){char path[256] = {0};if(getcwd(path,256) == NULL){perror("getcwd error!\n");exit(1);}   DIR *pdir = opendir(path);if(pdir == NULL){   perror("opendir error!\n");exit(1);}   struct dirent *s = NULL;while((s=readdir(pdir))!=NULL){   if(strncmp(s->d_name,".",1)==0){   continue;}   //是目录文件打印为蓝色,不是目录文件分为两种,普通文件是黑色,可执行文件是绿色struct stat filestat;stat(s->d_name,&filestat);if(S_ISDIR(filestat.st_mode)){printf("\033[1;34m%s\033[0m ",s->d_name);}else{if(filestat.st_mode &(S_IXUSR|S_IXGRP|S_IXOTH)){printf("\033[1;32m%s\033[0m ",s->d_name);}elseprintf("%s  ",s->d_name);}}printf("\n");closedir(pdir);exit(0);
}

http://www.xdnf.cn/news/1700.html

相关文章:

  • STM32F407使用ESP8266实现阿里云OTA(中)
  • 第9章 多模态大语言模型
  • Android 智能家居开发:串口是什么,为什么android版本都比较低?粘包半包的原因以及处理思路,缓冲区处理,以及超时清空缓冲区....
  • 操作系统进程管理笔记
  • python 函数与模块
  • 项目中的政治斗争如何化解
  • 如何在 Windows上安装 Python 3.6.5?
  • Python 中 `r` 前缀:字符串处理的“防转义利器”
  • 第十三届蓝桥杯 2022 C/C++组 修剪灌木
  • Blender插件 三维花草植物自然景观生成器 Geo-Scatter 5.4.0
  • MODIS(MOD11A2)中国2000-2024年度平均地表温度(LST)数据集
  • AI下半场,出现了“超体”时刻
  • ctfhow——web入门214~218(时间盲注开始)
  • 13-DevOps-引入容器编排Kubernetes
  • 使用vue2开发一个在线旅游预订平台-前端静态网站项目练习
  • 6.学习笔记-SpringMVC-拦截器(P71-P74)
  • 得物业务参数配置中心架构综述
  • 离线部署kubernetes
  • DeepSeek系列(7):行业专属应用
  • Unity后处理全解析:从入门到优化
  • 序论文42 | patch+MLP用于长序列预测
  • C语言教程(十四):C 语言指针详解
  • 倚光科技:微透镜阵列低成本加工新范式
  • 【数据可视化-27】全球网络安全威胁数据可视化分析(2015-2024)
  • Linux基础命令
  • 容器修仙传 我的灵根是Pod 第10章 心魔大劫(RBAC与SecurityContext)
  • 免费版还是专业版?Dynadot 域名邮箱服务选择指南
  • 深度学习物理信息神经网络PINN+大模型辅助编程​
  • 如何在 Postman 中,自动获取 Token 并将其赋值到环境变量
  • 整平机:精密制造的“隐形守护者”