編寫程序,實現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.pswp.cn/news/696577.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696577.shtml
英文地址,請注明出處:http://en.pswp.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天精通鴻蒙》 …

代碼隨想錄算法訓練營第四十二天|122. 買賣股票的最佳時機 II

674. 最長連續遞增序列 public static int findLengthOfLCIS(int[] nums) {int[] dp new int[nums.length];dp[0] 1;for (int i 1; i < nums.length; i) {dfs(nums, dp, i);}Arrays.sort(dp);return dp[dp.length - 1];}public static void dfs(int[] nums, int[] dp, i…

【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; 首先來說一下小店的主體類型…

git常用命令記錄

1、第一次初始化 git init git add . git commit -m ‘first commit’ git remote add origin gitgithub.com:帳號名/倉庫名.git git pull origin master git push origin master # -f 強推 git clone gitgithub.com:git帳號名/倉庫名.git 2、工作基本操作 git checkout master…

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;用戶可以選…

C語言——static的三大用法

被稱為面試愛考愛問題的它到底有何奧義 它難度不大并且非常常用&#xff0c;話不多說&#xff0c;直接開始 一、局部靜態變量 定義 在函數內部使用static修飾的變量被稱為局部靜態變量&#xff0c;與普通的局部變量不同&#xff0c;局部靜態變量在使用后不會被銷毀&#xff…

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的事務

事務是啥 MySQL的事務就是把多個sql語句操作打包在一起執行&#xff0c;要么全部執行&#xff0c;要么一個都別執行。這種操作稱為“原子性”&#xff0c;是事務最核心的特征。當某個sql操作出錯時&#xff0c;就會進行“回滾/rollback”操作&#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…