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