基于Linux系统用C语言实现myshell(minishell)功能实现

  1. 背景描述

         我们都知道, 计算机技术不但影响着我们的各行各业,Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

 

  1. 用户用例

在 Linux 中,进程控制有四种状态:创建、退出、等待、替换。为了 验证 或 应用 以上四种进程状态,所以有了下面 minishell 的实现。

Linux 中的 shell ,是指一个面向用户的命令接口,表现形式就是一个可以由用户录入的交互界面,其相当于 Windows 上 cmd 命令行。而下述程序为 shell 程序的简易版,只是简单实现了其中的一部分功能。

shell这个单词的英文含义为“壳”。顾名思义,Shell就像是一个外壳一样。就我理解而言,Shell本身是一段程序,它运行起来后,可以和内核来打交道。它是相对于内核来说的,建立在内核的基础上,面向于用户的一种表现形式。就好比我们看到一个球体,见到的只是外壳,并非内核。

Linux中的shell,是指一个面向用户的命令接口,表现形式就是一个可以由用户录入的界面,这个界面也可以反馈运行信息。

大概阐述

  • Main.c: 主要用于调用Terminal.c以及Command.c中的函数接口
  • Terminal.c: 用于实现终端的打印及接收命令,判断命令调用Command.c等操作
  • Command.c: 用于实现将传递进来的命令正确无误的操作进行,如ls,cd,mv, cp等等基本命令
  • Public: 主要用于存放公共头文件
  • Terminal.h和Command.h: 存放模块头文件

 

3.Minishell功能

ls                           ->                           查询当前目录文件 

ls -a                       ->                           查询当前目录文件包括隐藏文件

ls -l                        ->                           查询当前目录文件详情

touch                    ->                           新建文件

rm                         ->                           删除文件

mkdir ->                           新建文件夹

rmdir  ->                           删除文件夹

cd                          ->                           进入目标文件夹

cp              ->    拷贝文件

mv ->    移动/重命名文件

pwd ->    在终端显示当前路径

cat ->    在终端显示文件类型

chmod  ->    改变文件权限操作

ln  ->    创建文件硬链接

ln -s  ->    创建文件软连接

***具有终端输入日记记录功能,time.txt文件实时记录终端情况***

13d6125c942441e58868f936b2499cd6.png

 

 

切记   3   个   模块                      

(1)主模块

(2)功能模块

(3)执行模块

 


Public头文件

#ifndef __PUBLIC_H__
#define __PUBLIC_H__

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

#define MAX_ORDER_LEN         10

#endif

功能模块头文件

#ifndef __TERMINAL_H__
#define __TERMINAL_H__

#define   USER      "linux@ChenXi:"    //用户名

extern void ShowTerminal(void);
extern int ReadTerminal(char *pOrder,int maxlen);
extern int AnalysisTerminal(char *prOder,char **pAnalysisOrder,int maxlen);
extern int DoTerminal(char **pAnalysisOrder,int sum);






#endif

执行模块头文件

#ifndef __COMMAND_H__
#define __COMMAND_H__

extern void myls(void);
extern void myls_l(void);
extern void myls_a(void);
extern void mycd(char **AnalysisOrder,int sum);
extern void mytouch(char **pAnalysisOrder,int sum);
extern void myrm(char **pAnalysisOrder,int sum);
extern void mymkdir(char **pAnalysisOrder,int sum);
extern void myrmdir(char **pAnalysisOrder,int sum);
extern void mycp(char *psrc,char *pdst);
extern void mymv(char *old,char *new);
extern void mypwd(void);
extern void mycat(char *file);
extern void Statfile(char *pfilename);
extern void GetTime(char *pOrder);
extern void mychmod(char *filenum,char *filename);
extern void myln(char *file,char *new);
extern void myln_s(char *file,char *new);


#endif

 

主模块

#include "Public.h"
#include "Command.h"
#include "Terminal.h"


int main(int argc, char const *argv[])
{
          char Order[1024] = {0};                                             //命令数组
          char *AnalysisOrder[MAX_ORDER_LEN] = {NULL}; //解析命令指针数组
          int sum = 0;                                                                    //命令模块个数
          while(1)
          {

          
                    ShowTerminal();                                            //终端显示

                    memset(Order,0,sizeof(Order));                   // 每次接收命令前清空数组
                    ReadTerminal(Order,sizeof(Order));           //接收命令

                    sum = AnalysisTerminal(Order,AnalysisOrder,MAX_ORDER_LEN); //解析命令

                    DoTerminal(AnalysisOrder,sum);

          }

          

          return 0;
}

 

功能模块

#include "Public.h"
#include "Terminal.h"
#include "Command.h"


/*
 *终端的显示函数(获取当前文件路径)
 */
void ShowTerminal(void)
{
          char showbuf[1024] = {0};                                        //定义存放路径的数组
          char *pbuf = NULL;                                                    //路径指针

          getcwd(showbuf,sizeof(showbuf));                     //将当前路径存放进数组
          pbuf = showbuf + strlen(showbuf);                     //指针定位到/0
          while ('/' != *pbuf && pbuf >= showbuf)                                                   //指针定位到/
          {
                    pbuf--;
          }
          ++pbuf;                                                                       //定位到显示路径

          printf(USER"/%s#",pbuf);                             //打印终端显示
                                                                  //清除读写缓冲区
          return;
}

/*
 *接受终端命令函数
 *传参:  (命令数组)    (数组大小限制)
 */
int ReadTerminal(char *pOrder,int maxlen)
{
          fgets(pOrder,maxlen,stdin);                                //从终端接收命令传进Order数组
          pOrder[strlen(pOrder)- 1] = '\0';                        //将fgets接到的末尾的\n变为字符串结束标志\0
          GetTime(pOrder);
          
          return 0;
}

/*
 ********解析命令*******
 *传参:(命令数组)(解析命令指针数组)(数组大小限制)
 *返回值:一个命令的分块个数   
 */
int AnalysisTerminal(char *pOrder,char **pAnalysisOrder,int maxlen)
{
          int count = 0;
          char *pTmp = NULL;                                                     //分块一个命令个数的指针

          pTmp = strtok(pOrder," ");                                        //接收进第一个命令块
          
          if(NULL ==  pTmp)                                                     //未接受命令返回0
          {
                    return 0;
          }
          else                                                                              
          {
                    pAnalysisOrder[count] = pTmp;                //将接收到的第命令(第一个块)放进指针数组
                    count++; 
          }
          while(NULL != (pTmp = strtok(NULL," ")))         //将其他模块命令依次放入指针数组
          {
                    pAnalysisOrder[count] = pTmp;
                    count++;
          }
          pAnalysisOrder[count] = NULL;                          //指针数组最后一位空格给NULL
          
          return count ;        //返回命令分块个数
}

/*
 ********执行命令*******
 *传参:(解析命令指针数组)(一个命令的模块数量)
 *返回值:一个命令的分块个数   
 */
int DoTerminal(char **pAnalysisOrder,int sum)
{
          

                                                             /*==========ls类型===============*/
          if (1 == sum && !strcmp(pAnalysisOrder[0],"ls"))        //pAnalysisOrder[0]是一个指针,不能 ==
          {
                    myls();                                                                           
          }
          else if (2 == sum && !strcmp(pAnalysisOrder[1],"-l"))
          {
                    myls_l();
          }
          else if (2 == sum && !strcmp(pAnalysisOrder[1],"-a"))
          {
                    myls_a();
          }
         /* else if (2 == sum && !strcmp(pAnalysisOrder[1],"文件名"))
          {
                    myls_filename();
          }*/
           else if (3 == sum && !strcmp(pAnalysisOrder[1],"-l"))
          {
                    
          }

                                                            /*===========cd切换路径=========*/
          if ( !strcmp(pAnalysisOrder[0],"cd"))       
          {
                    mycd(pAnalysisOrder,sum);                                                                           
          }
                    
                                                         /*===========touch创建文件=========*/
          if (!strcmp(pAnalysisOrder[0],"touch"))
          {
                    mytouch(pAnalysisOrder,sum);
          }

                                                            /*=========rm删除文件==================*/
          if (!strcmp(pAnalysisOrder[0],"rm"))
          {
                    myrm(pAnalysisOrder,sum);
          }
                                                           /*=========mkdi创建文件夹r==================*/
          if (!strcmp(pAnalysisOrder[0],"mkdir"))
          {
                    mymkdir(pAnalysisOrder,sum);
          }
                                                          /*=========rmdir删除文件夹==================*/
          if (!strcmp(pAnalysisOrder[0],"rmdir"))
          {
                    myrmdir(pAnalysisOrder,sum);
          }
                                                         /*=========cp拷贝==================*/
          if (!strcmp(pAnalysisOrder[0],"cp"))
          {
                    mycp(pAnalysisOrder[1],pAnalysisOrder[2]);
          }
                                                         /*=========mv移动/重命名==================*/
          if (!strcmp(pAnalysisOrder[0],"mv"))
          {
                    mymv(pAnalysisOrder[1],pAnalysisOrder[2]);
          }
                                                            /*=========pwd获取当前路径==================*/
          if (!strcmp(pAnalysisOrder[0],"pwd"))
          {
                    mypwd();                 
          }
                                                           /*=========cat将文件打印在终端==================*/
          if (!strcmp(pAnalysisOrder[0],"cat"))
          {
                    mycat(pAnalysisOrder[1]);       
          }
                                                  /*=========chmod==================*/
          if (!strcmp(pAnalysisOrder[0],"chmod"))
          {
                    mychmod(pAnalysisOrder[1],pAnalysisOrder[2]);       
          }
                                                  /*=========ln==================*/
          if (!strcmp(pAnalysisOrder[0],"ln") && strcmp(pAnalysisOrder[0],"ln"))
          {
                    myln(pAnalysisOrder[1],pAnalysisOrder[2]);       
          }
          else if (!strcmp(pAnalysisOrder[0],"ln") && !strcmp(pAnalysisOrder[1],"-s"))
          {
                    myln_s(pAnalysisOrder[2],pAnalysisOrder[3]);       
          }







          return 0;

}

 

执行模块

#include "Public.h"
#include "Command.h"
#include "Terminal.h"


void myln(char *file,char *new)
{
   int ret = 4;

   ret = link(file,new);
   printf("%d\n",ret);
}
void myln_s(char *file,char *new)
{
   int ret = 4;

   ret = symlink(file,new);
   if(-1 == ret)
   {
   perror("fail to ln-s");
   }
}
/*
 *======日志函数======
 */
void GetTime(char *pOrder)
{
          int fd = 0;
          fd = open("time.txt",O_WRONLY | O_APPEND | O_CREAT,0664);
          if(-1 == fd)
          {
                    perror("fail to open time.txt");
                    return;
          }
          struct stat finformation;//存放文件的信息
          int ret = 0;

          ret = lstat("time.txt",&finformation);//获取信息给finformation

          if(-1 == ret)//判断是否获取成功
          {
                    perror("fail to lstat");
                    return;
          }
          struct tm *ptime = NULL;//最近命令时间
          char time[128] ={0};
          char *mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
          ptime = localtime(&finformation.st_ctime);
          sprintf(time," %d年%s %d %d:%d :%d 命令:         ",ptime->tm_year+1900,mon[ptime->tm_mon],ptime->tm_mday
                                                                                                    ,ptime->tm_hour,ptime->tm_min,ptime->tm_sec);

          write(fd,time,strlen(time));
          write(fd,pOrder,strlen(pOrder));
          write(fd,"\n",1);
          


          close(fd);
          return;
}
/*
 *======myls查看当前目录文件======
 */
void myls(void)
{
          DIR *fp = NULL;
          fp = opendir(".");
          if(NULL == fp)
          {
                    perror("fail to opendir(.)");
                    return;
          }

          struct dirent *pfile = NULL;
          while(NULL != (pfile = readdir(fp)))
          {
                    if('.' == pfile->d_name[0])
                    {
                              continue;
                    }
                    printf("%s   ",pfile->d_name);
          }
          printf("\n");
          closedir(fp);
          return;
          
}
/*
 *======chmod======
 */
void mychmod(char *filenum,char *filename)
{
   printf("filenum = %s\n",filenum);
   printf("filename= %s\n",filename);
   int modenum = 0;
   int one = 0;
   int two = 0;
   int three = 0;
   int mode = 0;
   modenum = atoi(filenum);
   
   three = modenum / 100;
   two = (modenum / 10) % 10;
   one = modenum % 10;

   mode = three * 8 * 8 +two * 8 + one;

   chmod(filename,mode);
}
/*
 *======ls_l======
 */
void myls_l(void)
{
         DIR *fp = NULL;
          fp = opendir(".");
          if(NULL == fp)
          {
                    perror("fail to opendir(.)");
                    return;
          }

          struct dirent *pfile = NULL;
          char filename[4096] = {0};
          while(NULL != (pfile = readdir(fp)))
          {
                    if('.' == pfile->d_name[0])
                    {
                              continue;
                    }
                    sprintf(filename,"%s",pfile->d_name);
                    Statfile(filename);
          }
           closedir(fp);
          return;
}
void Statfile(char *pfilename)
{         
          struct stat finformation;//存放文件的信息
          int ret = 0;

          ret = lstat(pfilename,&finformation);//获取信息给finformation

          if(-1 == ret)//判断是否获取成功
          {
                    perror("fail to lstat");
                    return;
          }
          switch(finformation.st_mode & __S_IFMT)//文件类型
          {
                    case __S_IFBLK :putchar('b');break;
                    case __S_IFCHR:putchar('c');break;
                    case __S_IFDIR :putchar('d');break;
                    case __S_IFREG:putchar('-');break;
                    case __S_IFLNK:putchar('l');break;
                    case __S_IFSOCK :putchar('s');break;
                    case __S_IFIFO :putchar('p');break;
          }
          finformation.st_mode & S_IRUSR ? putchar('r') : putchar('-');//创建者权限
          finformation.st_mode & S_IWUSR ? putchar('w') : putchar('-');
          finformation.st_mode & S_IXUSR ? putchar('x') : putchar('-');

          finformation.st_mode & S_IRGRP ? putchar('r') : putchar('-');//同组人员权限
          finformation.st_mode & S_IWGRP ? putchar('w') : putchar('-');
          finformation.st_mode & S_IXGRP ? putchar('x') : putchar('-');

          finformation.st_mode & S_IROTH ? putchar('r') : putchar('-');//其余人权限
          finformation.st_mode & S_IWOTH ? putchar('w') : putchar('-');
          finformation.st_mode & S_IXOTH ? putchar('x') : putchar('-');

          printf(" %ld",finformation.st_nlink);//硬链接个数

          struct passwd *puid = NULL;//uid名
          puid = getpwuid(finformation.st_uid);
          printf(" %s",puid->pw_name);

          struct group *pgid = NULL;//gid名
          pgid = getgrgid(finformation.st_gid);
          printf(" %s",pgid->gr_name);

          printf(" %5ld",finformation.st_size);//文件大小

          struct tm *ptime = NULL;//最近编辑时间
          char *mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
          ptime = localtime(&finformation.st_ctime);
          printf(" %s%d  %d:%d %s\n",mon[ptime->tm_mon],ptime->tm_mday,ptime->tm_hour
                                                            ,ptime->tm_min,pfilename);

         
}

/*
 *======ls_a===========
 */
void myls_a(void)
{
         DIR *fp = NULL;
          fp = opendir(".");
          if(NULL == fp)
          {
                    perror("fail to opendir(.)");
                    return;
          }

          struct dirent *pfile = NULL;
          while(NULL != (pfile = readdir(fp)))
          {
                    printf("%s   ",pfile->d_name);
          }
          printf("\n");
          closedir(fp);
          return; 
}
/*
 *======ls_file===========
 */

/*
 *======ls_l_file===========
 */



/*
 *======cd======切换文件夹
 */
void mycd(char **pAnalysisOrder,int sum)
{
          if(NULL != pAnalysisOrder[1])
          {
                    chdir(pAnalysisOrder[1]);
          }
          return;
}

/*
 *======touch======创建文件
 */
void mytouch(char **pAnalysisOrder,int sum)
{
          int fd = 0;
          if(NULL != pAnalysisOrder[1])
          {
                    fd = open(pAnalysisOrder[1],O_WRONLY | O_CREAT | O_APPEND,0777);//给写和创建权限
                    if(-1 == fd)
                    {
                              perror("fail to touch");
                              return;
                    }        
          }

          return;
}

/*
 *======rm======删除文件
 */
void myrm(char **pAnalysisOrder,int sum)
{
          if(NULL != pAnalysisOrder[1])
          {
                    remove(pAnalysisOrder[1]);
          }
       return;
}
/*
 *======mkdir======创建文件夹
 */
void mymkdir(char **pAnalysisOrder,int sum)
{
          if(NULL != pAnalysisOrder[1])
          {
                    mkdir(pAnalysisOrder[1],0777);         
          }
          return;
}
/*
 *======rmdir======删除文件夹
 */
void myrmdir(char **pAnalysisOrder,int sum)
{
          if(NULL != pAnalysisOrder[1])
          {
                    rmdir(pAnalysisOrder[1]);     
                        
          }
          return;
}
/*
 *======cp======拷贝文件
 */
void mycp(char *psrc,char *pdst)
{
          int fsrc = 0;
          int fdst = 0;
          char str[4096] = {0};

          fsrc = open(psrc,O_RDONLY);
          fdst = open(pdst,O_WRONLY | O_TRUNC | O_CREAT,0664);  // 110 110 100

          if(-1 == fsrc || -1 == fdst)
          {
                    perror("fail to mycp_open");
                    return;
          }
         
          read(fsrc,str,sizeof(str));
          write(fdst,str,strlen(str));
          close(fsrc);
          close(fdst);
          return;
}
/*
 *======mv======移动重命名
 */
void mymv(char *old,char *new)
{
          rename(old,new);
          return;
}
/*
 *======pwd======获取当前路径
 */
void mypwd(void)
{
          char path[256] = {0};
          getcwd(path,sizeof(path));
          printf("%s\n",path);
          return ;
}
/*
 *======cat======文件打印在终端
 */
void mycat(char *file)
{
          int ff = 0;
          char word[8192] = {0};

          ff= open(file,O_RDONLY);
          if(-1 == ff)
          {
                    perror("fail to mycat");
                    return;
          }
         
          read(ff,word,sizeof(word));
          printf("%s",word);
          close(ff);
        
          return;
}

 

 

 

  • 14
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨CX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值