编写程序,实现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以及历史记录

  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值