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操作了
接下来给大家演示一下: