MiniShell 项目总结 2月21~22日总结

一、项目说明

利用Linux中IO接口实现 terminal 的shell命令 制作成一个minishell 的可执行文件

输出形式为:

[linux@Ubuntu:当前所在目录]	

项目要求:

一、基本实现

  1.         cd
  2.         ls 
  3.         ls -l
  4.         ls -a
  5.         pwd
  6.         mkdir
  7.         mv
  8.         rm
  9.         rmdir
  10.         cp
  11.         touch
  12.         cat
  13.         ln

这13个shell 命令

  二、将用户输入命令的时间及其命令写入到日志文件中并纪录
  三、根据代码功能,将代码划分成若干个文件,并使用多文件编程来实现代码

 二、实现思路

1.打印终端命令行如何实现?
        [linux@Ubuntu:当前所在目录]                getcwd -> 绝对路径 -> 显示最后一部分内容
                                                                         /home/linux/Desktop/dirname

2.能够接收用户的命令?
        ls                                       fgets -> 解析字符串获得命令及其参数
        touch a.txt                             
        rmdir dirname 
        cp a.txt b.txt 

* 难点在于如何解析输入进去的字符串

        后面有三种方法:分别是 1.切割字符串存入新的字符串中

                                                 2.使用指针 

                                                3.使用strtok函数

将获得的一段段字符串分别进行传参。

3.实现对应命令?
        ls                                       opendir readdir closedir 
        ls -a                                   opendir readdir closedir 
        ls -l                                   
        touch                                   fopen fclose 
        rm                                    remove 
        mkdir                                   mkdir 
        rmdir                                   rmdir 
        cp                                       IO 
        cat                                      IO 
        ln                                    symlink link 
        pwd                                   getcwd 
        cd                                    chdir 

        mv                                    rename 
        chmod                                 chmod 


4.命令记录
        写入文件                              fopen fprintf fclose

三、具体实现

 分为

main.c

command.c

command.h

terminal.c

terminal.h

record.c

record.h

record.txt

makfile  (进行链接)

首先是 main.c  其中定义了 接收命令的数组


#include<stdio.h>
#include<string.h>
#include"terminal.h"
#include"command.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"))
        {
            break;
        }

        curcmdlen = SplitCommand(command,parg,10);
        ExecCommand(parg,curcmdlen);
    }

    return 0;
}

command.c

#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<dirent.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
int Myls(void)
{
    DIR *dp = NULL;
    struct dirent *pp =NULL;

    dp = opendir(".");
    if(NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while(1)
    {
        pp = readdir(dp);
        if(NULL == pp)
        {
            break;
        }

        if('.' == pp->d_name[0])
        {
            continue;
        }
        printf("%s  ",pp->d_name);
    }
    putchar('\n');
    closedir(dp);
    return 0;
}

int Myls_a(void)
{
    DIR *dp = NULL;
    struct dirent *pp =NULL;

    dp = opendir(".");
    if(NULL == dp)
    {
        perror("fail to opendir");
        return -1;
    }

    while(1)
    {
        pp = readdir(dp);
        if(NULL == pp)
        {
            break;
        }
        printf("%s  ",pp->d_name);
    }
    putchar('\n');
    closedir(dp);
    return 0;
}
int DisplayFile(char *pfilename)
{
    struct stat buf;
    int ret = 0;
    struct passwd *pwd =NULL;
    struct group *grp = NULL;
    struct tm *ptm =NULL;
    char tmpbuff[1024] = {0};
    char *mon[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

    ret = lstat(pfilename,&buf);
    if(-1 == ret)
    {
        perror("fail to lstat");
        return -1;
    }

    if(S_ISBLK(buf.st_mode))
    {
        putchar('b');
    }
    else if(S_ISCHR(buf.st_mode))
    {
        putchar('c');
    }
    else if(S_ISDIR(buf.st_mode))
    {
        putchar('d');
    }
    else if(S_ISREG(buf.st_mode))
    {
        putchar('-');
    }
    else if(S_ISLNK(buf.st_mode))
    {
        putchar('l');
    }
    else if(S_ISSOCK(buf.st_mode))
    {
        putchar('s');
    }
    else if(S_ISFIFO(buf.st_mode))
    {
        putchar('p');    
    }

    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);
    printf(" %s",pwd->pw_name);

    grp = getgrgid(buf.st_gid);
    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",pfilename);

    if(S_ISLNK(buf.st_mode))
    {
        readlink(pfilename,tmpbuff,sizeof(tmpbuff));
        printf("->%s",tmpbuff);
    }

    printf("\n");

    return 0;
}

int Myls_l(void)
{
    DIR *dp = NULL;
    struct dirent*pp = NULL;

    dp = opendir(".");
    if(NULL == dp)
    {
        perror("fial to opendir");
        return -1;
    }

    while(1)
    {
        pp = readdir(dp);
        if(NULL == pp)
        {
            break;
        }

        if('.' == pp->d_name[0])
        {
            continue;
        }

        DisplayFile(pp->d_name);
    }
    closedir(dp);
    return 0;
}

int Touch(const char *filename)
{
    FILE *fp = NULL;

    fp = fopen(filename,"w");
    if(NULL == fp)
    {
        perror("fail fopen");
        return -1;
    }
    
    fclose(fp);

    return 0;

}

int Cp(const char *file1,const char *file2)
{
    FILE *fsrc = NULL;
    FILE *fdst = NULL;
    size_t nret = 0;
    char tmpbuff[4096] = {0};

    fsrc = fopen(file1,"r");
    if(NULL ==fsrc)
    {
        perror("fail to fopen");
        return -1;
    }

    fdst = fopen(file2,"w");
    if(NULL == fdst)
    {
        perror("fail to open");
        return -1;
    }

    while(1)
    {
        nret =fread(tmpbuff,1,sizeof(tmpbuff),fsrc);
        if(0 == nret)
        {
            break;
        }

        fwrite(tmpbuff,1,nret,fdst);
    }

    fclose(fsrc);
    fclose(fdst);

    return 0;
}
int Cat(char *pcmdbuf)
{
    FILE *fp = NULL;
    size_t ret = 0;
    int i = 0;
    char tmpbuff[4096] = "0";

    fp = fopen(pcmdbuf,"r");
    if(NULL == fp)
    {
        perror("fail to open");
        return -1;
    }
    ret=fread(tmpbuff,1,sizeof(tmpbuff),fp);
    for(i = 0;i<ret;++i)
    {
        printf("%c",tmpbuff[i]);
    }
    fclose(fp);
    return 0;
}
int Pwd(char* pcmdbuf)
{
    char tmpbuff[4096] ={0};
    getcwd(tmpbuff,sizeof(tmpbuff));
    printf("%s\n",tmpbuff);
    return 0;
}
int Ln(char *file1,char *file2)
{
    link(file1,file2);
    return 0;
}

int Mychmod(char *pcmdbuf,char *mode)
{
    int ret = 0;
    int len = strlen(mode);
    int num = 0;
    int i,j;
    int a[len];

    for(i = 0;i< len ;++i,++mode)
    {
        a[i] = *mode -48;
    }

    for(i = len -1,j = 1;i>=0;--i,j*=10)
    {
        num += a[i]*j;
    }

    chmod(pcmdbuf,num);
    return 0;
}

command.h

#ifndef _COMMAND_H
#define _COMMAND_H

extern int Myls(void);
extern int Myls_a(void);
extern int DisplayFile(char *pfilename);
extern int Myls_l(void);
extern int Touch(const char *filename);
extern int Cp(const char *file1,const char *file2);
extern int Cat(char *pcmdbuf);
extern int Pwd(char* pcmdbuf);
extern int Ln(char *file1,char *file2);
extern int Mychmod(char *pcmdbuf,char *mode);

#endif

terminal.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include"command.h"
/*********************************
 * File Name:ShowTerminal
 * Parameter: void
 * Return value :  succes >0
 *                 fail   >-1
 ********************************/
int ShowTerminal(void)
{
    char tmpbuff[1024] = {0};
    char *ptmp = NULL;

    getcwd(tmpbuff,sizeof(tmpbuff));

    ptmp = tmpbuff + strlen(tmpbuff); // 首地址+字符串长度 尾 ‘/0’ 的地址
    while(*ptmp != '/')
    {
        ptmp--;
    }
    if(strcmp(tmpbuff,"/"))
    {
        ptmp++;
    }

    printf("[linux@Ubuntu:%s]",ptmp);

    return 0;
}
/*********************************
 * File Name:GetCommand
 * Parameter:  
 *          pcmdbuff:存放命令空间首地址
 *          maxlen:最大存放字符串个数
 * Return value :  succes >0
 *                 fail   >-1
 ********************************/
 int GetCommand(char *pcmdbuff,int maxlen)
 {
    fgets(pcmdbuff,maxlen,stdin);
    pcmdbuff[strlen(pcmdbuff)-1] = '\0';

    return 0;
 }

/*********************************
 * File Name:SplitCommand 解析命令 把命令分成小段 返回小段的个数
 * Parameter:  
 *          pcmdbuff:存放命令空间首地址
 *          maxlen:最大存放字符串个数
 *          parg:存放解析后字符串地址的指针数组
 * Return value :  succes >解析到命令的个数
 *                 fail   >-1
 ********************************/
 int SplitCommand(char *pcmdbuff,char **parg,int maxlen) // char **parg == char *parg[]
 {
    char *ptmp = NULL;
     int cnt = 0;

     ptmp = pcmdbuff;

     while(1)
     {
        parg[cnt] = ptmp;
         cnt++;
         while(*ptmp != '\0' && *ptmp != ' ')//指针在遇到‘ ’或最后的‘\0’时停下
         {
            ptmp++;
         }
         if('\0'== *ptmp)
         {
            break;
         }

         *ptmp = '\0';//给每个命令段后面补上 ‘\0’使其成为一个字符串

         ptmp++;
         while(*ptmp == ' ')
         {
            ptmp++;
         }
     }

     return cnt;
 }

/*********************************
 * File Name:ExecCommand  判断命令 
 * Parameter:  
 *          curlen:命令的个数
 *          parg:存放解析后字符串地址的指针数组
 * Return value :  succes >0
 *                 fail   >-1
 ********************************/
int ExecCommand(char **parg ,int curlen)
{
    if(!strcmp(parg[0],"ls"))
    {
        if(2 == curlen && !strcmp(parg[1],"-l"))
        {
            Myls_l();
            return 0;
        }
        else if(2 == curlen && !strcmp(parg[1],"-a"))
        {
            Myls_a();
            return 0;
        }
        Myls();
    }
    else if(!strcmp(parg[0],"cp"))
    {
        Cp(parg[1],parg[2]);
    }
    else if(!strcmp(parg[0],"cat"))
    {
        Cat(parg[1]);
    }    
    else if(!strcmp(parg[0],"pwd"))
    {
        Pwd(parg[1]);
    } 
    else if(!strcmp(parg[0],"ln"))
    {
        Ln(parg[1],parg[2]);
    }
    else if(!strcmp(parg[0],"cd"))
    {
        chdir(parg[1]);
    }
    else if(!strcmp(parg[0],"touch"))
    {
        Touch(parg[1]);
    }
    else if(!strcmp(parg[0],"mkdir"))
    {
        mkdir(parg[1],0777);
    }
    else if(!strcmp(parg[0],"rmdir"))
    {
        rmdir(parg[1]);
    }
    
    else if(!strcmp(parg[0],"rm"))
    {
        remove(parg[1]);
    }
    else if(!strcmp(parg[0],"ln"))
    {
        Ln(parg[1],parg[2]);
    }
    else if(!strcmp(parg[0],"chmod"))
    {
        Mychmod(parg[1],parg[2]);
    }

    return 0;
}

terminal.h

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

record.c

#include"record.h"
#include<stdio.h>
#include<time.h>
FILE *fp = NULL;

int InitRecord(void)
{
    fp = fopen(RECORD_PATH,"a");
    if(NULL == fp)
    {
        perror("fail fopen");
        return -1;
    }

    return 0;
}

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;
}

int DelnitRecord(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 DelnitRecord(void);

#endif

makefile

OBJ = minishell
OBJS += main.c
OBJS += terminal.c
OBJS += command.c
OBJS += record.c

$(OBJ):$(OBJS)
	gcc $^ -o $@

.PHONY:
	clean:
		rm$(OBJ)
install:
	sudo cp $(OBJ)  /bin
uninstall:
	sudo rm /bin/$(OBJ)

四、实现效果

五、项目总结

1.Terminal多窗口的使用可以更快捷方便的进行代码的调试

        以及vim 编辑器 的  vsp功能 分屏打开文件 利于 复制y  粘贴p

2.之前所学IO的多有不熟悉 ,需要翻阅笔记才能对照着打出来。

        一是不熟练,其次就是理解也不够深刻

3.对 man手册的使用更为熟练了 ,主要是对各个函数的参数进一步了解

4.对char *tmpbuf  与 char  tmpbuf[4096] ={0};

        以及加强char **p 和 char *p[]的理解

*************************************

Makefile

Makefile 是一种文本文件,通常用于描述软件项目的构建规则和依赖关系。它配合构建工具如 GNU Make,可以自动化构建过程,提高软件开发的效率。

strtok函数

char *strtok(char *str, const char *delim);

功能: 用于将字符串分割成多个子字符串

参数: 

  • str: 要分割的字符串,第一次调用时传入需要分割的字符串,后续调用传入 NULL 即可。
  • delim: 分割字符串时所用的分隔符,可以是单个字符或字符串。

 返回值:一个指向分割得到的子字符串的指针

strtok 函数在第一次调用时,会使用参数 str 指向的字符串进行分割操作,并返回第一个找到的子字符串。在后续调用中,如果传入 NULL 作为参数,strtok 函数会继续使用上一次的字符串进行分割并返回下一个子字符串,直到字符串被完全分割。在分割过程中,strtok 函数会修改参数 str 指向的字符串,在其中插入 NULL 终止符以分隔子字符串。

需要注意的是,由于 strtok 函数会修改传入的字符串,因此在多线程环境下需要谨慎使用。

#include <string.h>
#include <stdio.h>

int main(void)
{
	char cmdbuf[1024] = {0};
	char *pret = NULL;
	char *parg[10] = {NULL};
	int cnt = 0;

	//ln -s file.txt a.txt
	gets(cmdbuf);

	parg[cnt] = strtok(cmdbuf, " ");
	cnt++;
	
	while (1)
	{
		parg[cnt] = strtok(NULL, " ");
		if (NULL == parg[cnt])
		{
			break;
		}
		cnt++;
	}
	
	int i = 0;

	for (i = 0; i < cnt; i++)
	{
		printf("parg[%d] = %s\n", i, parg[i]);
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值