编写程序,实现shell功能——项目训练——day08

c

c今天做了一个实战项目训练,编写一个程序,实现shell功能,我们称之为minishell。

主要是利用Linux中IO接口实现,实现的功能有:

        1.ls        ls -a        ls -l        cd        cp        mv        pwd        cat        

        2.touch        rm        mkdir        rmdir        chmod        ln

首先,我们先进行编写主函数main.c

#include "head.h"    //包含各种头文件
#include "terminal.h"    
#include "record.h"   int main(void)
{char command[1024] = {0};    //接收字符串,定义到主函数是因为都要用到    char *parg[10] = {NULL};    //指针数组int curcmdlen = 0;          //查看输入InitRecord();while(1){ShowTerminal();                //显示终端GetCommand(command,1024);        //获取命令if(!strcmp(command,"exit"))    //如果输入的是exit退出{break;}RecordCommand(command);        //存储历史命令,做记录curcmdlen = SplitCommand(command,parg,10);    ExecCommand(parg,curcmdlen);    //输出}return 0;
}

head.h主要包含了所需要的头文件

#ifndef __HEAD_H__
#define __HEAD_H__#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<dirent.h>
#include<string.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>
#include<stdlib.h>#endif

接下来就开始编写函数terminal.c以及terminal.h了

#include"head.h"
#include "command.h"
/**********************************函数名:ShowTerminal*参  数:*		缺省*返回值:*		成功返回0
********************************/
int ShowTerminal(void)
{char tmpbuff[1024] = {0};char *ptmp = NULL;getcwd(tmpbuff,sizeof(tmpbuff));/*获得路径中最后一段目录文件名*/ptmp = tmpbuff + strlen(tmpbuff);while(*ptmp != '/'){--ptmp;}if(strcmp(tmpbuff,"/")){++ptmp;}printf("[linux@linux:%s]:",ptmp);return 0;
}/*********************************************************函数名:GetCommand*参  数:*		pcmdbuf:存放命令空间首地址*		maxlen:最大存放字符串个数*返回值:*		成功返回0*		失败返回-1*******************************************************/
int GetCommand(char *pcmdbuf,int maxlen)
{fgets(pcmdbuf,maxlen,stdin);pcmdbuf[strlen(pcmdbuf)-1] = '\0';return 0;
}/*********************************************************函数名:SplitCommand*参  数:*		pcmdbuf:存放命令空间首地址*		parg:存放解析后字符串地址的指针数组*		maxlen:最多解析命令的个数*返回值:*		成功返回解析到命令的个数*		失败返回-1*******************************************************/
int SplitCommand(char *pcmdbuf,char **parg,int maxlen)
{char *ptmp = NULL;int cnt = 0;ptmp = pcmdbuf;parg[cnt] = strtok(ptmp," ");cnt++;while(1)    //切割字符串{parg[cnt] = strtok(NULL," ");if(NULL == parg[cnt]){break;}cnt++;}return cnt;
}/*********************************************************函数名:ExecCommand*参  数:*		parg:存放解析后字符串地址的指针数组*		curlen:命令的个数*返回值:*		成功返回0*		失败返回-1*******************************************************/
int ExecCommand(char **parg,int curlen)
{if(!strcmp(parg[0],"ls")){MyLs(curlen,parg);}else if(!strcmp(parg[0],"cd")){MyCd(curlen,parg);}else if(!strcmp(parg[0],"touch")){MyTouch(curlen,parg);}else if(!strcmp(parg[0],"rm")){MyRm(curlen,parg);}else if(!strcmp(parg[0],"mkdir")){MyMkdir(curlen,parg);}else if(!strcmp(parg[0],"rmdir")){MyRmdir(curlen,parg);}else if(!strcmp(parg[0],"cp")){MyCp(curlen,parg);}else if(!strcmp(parg[0],"mv")){MyMv(curlen,parg);}else if(!strcmp(parg[0],"pwd")){MyPwd(curlen,parg);}else if(!strcmp(parg[0],"cat")){MyCat(curlen,parg);}else if(!strcmp(parg[0],"chmod")){MyChmod(curlen,parg);}else if(!strcmp(parg[0],"ln")){MyLn(curlen,parg);}return 0;
}

terminal.h文件

#ifndef __TERMINAL_H__
#define __TERMINAL_H__extern int ShowTerminal(void); 
extern int GetCommand(char *pcmdbuf,int maxlen);
extern int SplitCommand(char *pcmdbuf,char **parg,int maxlen);
extern int ExecCommand(char **parg,int curlen);#endif

接下来就是开始写命令函数了:command.c

#include"head.h"/*********************************************************函数名:MyCd*参  数:*		argc:命令的个数*		argv:存放解析后字符串地址的指针数组*返回值:*		成功返回0*		失败返回-1 *******************************************************/
int MyCd(int argc,char *argv[])
{if(argv[1] != NULL){chdir(argv[1]);}return 0;
}
int MyLs(int argc,char *argv[])
{DIR *dp = NULL;struct dirent *pp = NULL;struct passwd *pwd = NULL;struct group *grp = NULL;struct stat buf;struct tm *ptm = NULL;char tmpbuff[1024] = {0};int ret = 0;char *mon[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};dp = opendir(".");if(NULL == dp){perror("fail to opendir");return -1;}if(1 == argc){while((pp = readdir(dp)) != NULL){if('.' == *pp->d_name){continue;}printf("%-15s",pp->d_name);++ret;if(0 == ret % 5){putchar('\n');}}if(ret != 5){putchar('\n');}}if(2 == argc && !strcmp(argv[1],"-a")){while((pp = readdir(dp)) != NULL){printf("%-15s",pp->d_name);++ret;if(0 == ret % 5){putchar('\n');}}if(ret != 5){putchar('\n');}}if(2 == argc && !strcmp(argv[1],"-l")){while(1){pp = readdir(dp);if(NULL == pp){break;}if('.' == pp->d_name[0]){continue;}ret = lstat(pp->d_name,&buf);if(-1 == ret){perror("fail to stat");return -1;}switch(buf.st_mode & S_IFMT){case S_IFBLK:putchar('b');break;case S_IFCHR:putchar('c');break;case S_IFDIR:putchar('d');break;case S_IFIFO:putchar('p');break;case S_IFLNK:putchar('l');break;case S_IFREG:putchar('-');break;case S_IFSOCK:putchar('s');break;}buf.st_mode & S_IRUSR ? putchar('r'):putchar('-');buf.st_mode & S_IWUSR ? putchar('w'):putchar('-');buf.st_mode & S_IXUSR ? putchar('x'):putchar('-');buf.st_mode & S_IRGRP ? putchar('r'):putchar('-');buf.st_mode & S_IWGRP ? putchar('w'):putchar('-');buf.st_mode & S_IXGRP ? putchar('x'):putchar('-');buf.st_mode & S_IROTH ? putchar('r'):putchar('-');buf.st_mode & S_IWOTH ? putchar('w'):putchar('-');buf.st_mode & S_IXOTH ? putchar('x'):putchar('-');printf(" %ld",buf.st_nlink);pwd = getpwuid(buf.st_uid);if(NULL == pwd){printf(" %d",buf.st_uid);}else{printf(" %s",pwd->pw_name);}grp = getgrgid(buf.st_gid);if(NULL == grp){printf(" %d",buf.st_gid);}else{printf(" %s",grp->gr_name);}printf(" %5ld",buf.st_size);ptm = localtime(&buf.st_mtime);printf(" %s  %02d %02d:%02d",mon[ptm->tm_mon],ptm->tm_mday,ptm->tm_hour,ptm->tm_min);printf(" %s",pp->d_name);if(S_ISLNK(buf.st_mode)){readlink(pp->d_name,tmpbuff,sizeof(tmpbuff));printf(" -> %s",tmpbuff);}putchar('\n');}}closedir(dp);return 0;
}int MyTouch(int argc,char *argv[])
{FILE *p = NULL;int i = 0;for(i = 1;i < argc;++i){p = fopen(argv[i],"a");fclose(p);}return 0;
}int MyRm(int argc,char *argv[])
{int i = 0;for(i = 1;i < argc;++i){remove(argv[i]);}return 0;
}int MyMkdir(int argc,char *argv[])
{int i = 0;for(i = 1;i < argc;++i){mkdir(argv[i],0777);}return 0;
}int MyRmdir(int argc,char *argv[])
{int i = 0;for(i = 1;i < argc;++i){rmdir(argv[i]);}return 0;
}int MyCp(int argc,char *argv[])
{FILE *p = NULL;FILE *q = NULL;char ch[4096] = {0};p = fopen(argv[1],"r");q = fopen(argv[2],"a");while(1){if(NULL == fgets(ch,sizeof(ch),p)){break;}fputs(ch,q);}fclose(p);fclose(q);return 0;
}int MyMv(int argc,char *argv[])
{if(0 != rename(argv[1],argv[2])){perror("Error");return -1;}return 0;
}int MyPwd(int argc,char *argv[])
{char tmpbuff[4096] = {0};getcwd(tmpbuff,sizeof(tmpbuff));printf("%s\n",tmpbuff);return 0;
}int MyCat(int argc,char *argv[])
{FILE *fp = NULL;fp = fopen(argv[1],"r");char tmpbuff[4096] = {0};if(NULL == fp){perror("fail to fopen");return 0;}while(NULL != fgets(tmpbuff,sizeof(tmpbuff),fp)){printf("%s",tmpbuff);}fclose(fp);return 0;
}int MyChmod(int argc,char *argv[])
{char *fp = NULL;char *mode_str = NULL;mode_t mode = 0;fp = argv[1];mode_str = argv[2];mode = strtol(mode_str,NULL,8);chmod(fp,mode);return 0;
}int MyLn(int argc,char *argv[])
{link(argv[1],argv[2]);return 0;
}

command.h:

cat command.h
#ifndef __COMMAND_H__
#define __COMMAND_H__extern int MyLs(int argc,char *argv[]);
extern int MyCd(int argc,char *argv[]);
extern int MyTouch(int argc,char *argv[]);
extern int MyRm(int argc,char *argv[]);
extern int MyMkdir(int argc,char *argv[]);
extern int MyRmdir(int argc,char *argv[]);
extern int MyCp(int argc,char *argv[]);
extern int MyMv(int argc,char *argv[]);
extern int MyPwd(int argc,char *argv[]);
extern int MyCat(int argc,char *argv[]);
extern int MyChmod(int argc,char *argv[]);
extern int MyLn(int argc,char *argv[]);#endif

还有就是创建一个历史记录,使操作过的命令都有记录

record.c

#include "head.h"
#include "record.h"FILE *fp = NULL;/*********************************************************函数名:InitRecord*参  数:*		缺省 void*返回值:*		成功返回0*		失败返回-1*******************************************************/
int InitRecord(void)
{fp = fopen(RECORD_PATH,"a");if(NULL == fp){perror("fail to fopen");return -1;}return 0;
}/*********************************************************函数名:RecordCommand*参  数:*		pcmdbuf 命令字符串首地址*返回值:*		成功返回0*		失败返回-1*******************************************************/
int RecordCommand(char *pcmdbuf)
{time_t t;struct tm *ptm = NULL;time(&t);ptm = localtime(&t);fprintf(fp,"[%04d-%02d-%02d %02d:%02d:%02d]%s\n",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,pcmdbuf);fflush(fp);return 0;
}/*********************************************************函数名:DeInitRecord*参  数:*		缺省 void*返回值:*		成功返回0*		失败返回-1*******************************************************/
int DeInitRecord(void)
{if(fp != NULL){fclose(fp);fp = NULL;}return 0;
}

record.h

#ifndef __RECORD_H__
#define __RECORD_H__#define RECORD_PATH "./record.txt"extern int InitRecord(void);
extern int RecordCommand(char *pcmdbuf);
extern int DeInitRecord(void);#endif

以上,我们就实现了minishell操作了

接下来给大家演示一下:

先实现的是ls        ls -a        ls -l

实现了:touch        rm        mkdir        rmdir        cd         cp        cat

实现了:mv        pwd        chmod

实现了:ln以及历史记录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/696577.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件License授权原理

软件License授权原理 你知道License是如何防止别人破解的吗&#xff1f;本文将介绍License的生成原理&#xff0c;理解了License的授权原理你不但可以防止别人破解你的License&#xff0c;你甚至可以研究别人的License找到它们的漏洞。喜欢本文的朋友建议收藏关注&#xff0c;…

【Linux】进程状态

进程状态 进程状态的简要介绍运行状态进程排队 阻塞状态挂起状态Linux中的进程状态 进程状态的简要介绍 进程状态指的是一个操作系统中正在运行的进程当前所处的状态。根据不同的操作系统&#xff0c;进程状态可能会有一些细微的差别&#xff0c;但最主要的是以下三种状态 运行…

Java——方法的使用

目录 一.方法的概念及使用 1 什么是方法(method) 2.方法定义 3 方法调用的执行过程 4 实参和形参的关系(重要) 5.没有返回值的方法 二.方法重载 1.为什么需要方法重载 2.方法重载概念 3.方法签名 三.递归 1.递归的概念 2.递归执行过程分析 3. 递归练习 一.方法的…

猫头虎分享已解决Bug || 容器编排问题:OrchestrationFailure, ContainerManagementError

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【Python】【VS Code】VS Code中python.json和setting.json文件配置说明

目录 1. python.json配置 2. setting.json配置 3. 解决中文乱码 4. 实现效果 1. python.json配置 python.json 获取步骤&#xff1a;文件 -> 首选项 -> 配置用户代码片段 -> python 此为VS Code的头文件设置&#xff0c;复制以下内容到 python.json {"HEADER…

个人做抖店如何能够快速起店?掌握好技巧是关键!建议收藏!

大家好&#xff0c;我是电商小布。 相信我们每个朋友在店铺开通后&#xff0c;最关心的事情就是小店成功起店了。 那么个人做抖店想要快速起店&#xff0c;该怎么来进行操作呢&#xff1f; 接下来&#xff0c;小布重点给大家说三点&#xff1a; 首先来说一下小店的主体类型…

dell r740服务器黄灯闪烁维修现场解决

1&#xff1a;首先看一下这款DELL非常主力的PowerEdge R740服务器长啥样&#xff0c;不得不说就外观来说自从IBM抛弃System X系列服务器后&#xff0c;也就戴尔这个外观看的比较顺眼。 图一&#xff1a;是DELL R740前视图&#xff08;这款是8盘机型&#xff09; 图二&#xff…

QT 数据库的增加操作和画图 Win

第一步、先配置CMakeLists.txt 在CMakeLists.txt中添加 find_package(Qt6 REQUIRED COMPONENTS Sql) find_package(Qt6 REQUIRED COMPONENTS Charts)target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Sql) target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Charts)避…

springboot集成JWT实现token权限认证

vuespringboot登录与注册功能的实现 注&#xff1a;对于JWT的学习&#xff0c;首先要完成注册和登录的功能&#xff0c;本篇博客是基于上述博客的进阶学习&#xff0c;代码页也是在原有的基础上进行扩展 ①在pom.xml添加依赖 <!-- JWT --> <dependency><grou…

Linux篇:Shell命令以及运行原理 和 权限

一. Shell命令及原理 Linux操作系统狭义上是Linux内核&#xff0c;广义上是指Linux内核Linux外壳(Shell)和对应的配套程序 Linux外壳&#xff1a;Linux 外壳是用户与内核之间的接口&#xff0c;用户通过外壳与操作系统进行交互和操作。在 Linux 系统中&#xff0c;用户可以选…

pycharm 远程运行报错 Failed to prepare environment

什么也没动的情况下&#xff0c;远程连接后运行是没问题的&#xff0c;突然在运行时就运行不了了&#xff0c;解决方案 清理缓存&#xff1a; 有时候 PyCharm 的内部缓存可能出现问题&#xff0c;可以尝试清除缓存&#xff08;File > Invalidate Caches / Restart&#xff0…

mysql优化指南之原理篇

之前碰到一个线上问题&#xff0c;在接手一个同事的项目后&#xff0c;因为工期比较赶&#xff0c;我还没来得及了解业务背景和大致实现&#xff0c;只是了解了上线发布的顺序和验证方式就进行了上线&#xff0c;在上线进行金丝雀的时候系统还没发生什么异常&#xff0c;于是我…

MySQL数据库进阶第二篇(索引,SQL性能分析,使用规则)

文章目录 一、索引概述二、索引结构三、结构 - B-Tree四、结构 - BTree五、结构 - Hash六、索引分类七、索引语法1.案例代码 八、SQL性能分析1.查看SQl执行频率2.慢查询日志3.PROFILES详情4.EXPLAIN执行计划 九、 索引使用规则十、SQL 提示十一、覆盖索引十二、前缀索引十三、单…

滚动加载react-infinite-scroll-component

react-infinite-scroll-component 当请求数据量过大时&#xff0c;接口返回数据时间会很长&#xff0c;数据回显时间长&#xff0c;Dom 的渲染会有很大的性能压力。 antd的List组件中有提到一个滚动加载的组件库react-infinite-scroll-component 实现滚动加载 Antd&#xff1…

考研高数(高阶导数的计算)

1.归纳法 常见高阶导数 2.泰勒展开式 3.莱布尼兹公式 4.用导数定义证明导函数在某一点连续的例题

【kubernetes】二进制部署k8s集群之cni网络插件flannel和calico工作原理(中)

↑↑↑↑接上一篇继续部署↑↑↑↑ 目录 一、k8s集群的三种接口 二、k8s的三种网络模式 1、pod内容器之间的通信 2、同一个node节点中pod之间通信 3、不同的node节点的pod之间通信 Overlay Network VXLAN 三、flannel网络插件 1、flannel插件模式之UDP模式&#xff0…

2024/2/22

P8680 [蓝桥杯 2019 省 B] 特别数的和 题目描述 小明对数位中含有 2、0、1、9 的数字很感兴趣&#xff08;不包括前导 00&#xff09;&#xff0c;在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40&#xff0c;共28 个&#xff0c;他们的和是574。 请问&#xff0c;在…

【2024软件测试面试必会技能】

Unittest(5)&#xff1a;unittest_忽略用例 忽略用例 在执行测试脚本的时候&#xff0c;可能会有某几条用例本次不想执行&#xff0c;但又不想删也 不想注释&#xff0c;unittest通过忽略部分测试用例不执行的方式&#xff0c;分无条件忽略和有条 件忽略,通过装饰器实现所描述…

Vue3+vite搭建基础架构(11)--- 菜单栏功能和Tab页功能实现

Vue3vite搭建基础架构&#xff08;11&#xff09;--- 菜单栏功能和Tab页功能实现 说明删除项目中不需要的文件userStore全局属性代码菜单栏代码Tab页代码解决浏览器输入地址时不会打开tab页问题和切换tab页时参数丢失问题 说明 这里记录下自己在Vue3vite的项目使用less来写样式…