项目目标
1.编写函数打印初始界面以及显示输入的命令(由于程序一直执行,需要在循环内执行)
2.编写接收用户输入的命令的函数
3.编写使命令与功能匹配的函数
4.将界面输入的字符串分割为命令以及传入函数的数据
5.完成minishell的基本功能函数:
ls :显示目录下文件(不包括隐藏文件)
ls -a :显示所有文件
touch :创建一个文件
rm:移除一个文件
mkdir :创建一个目录
rmdir:移除一个目录
cd :切换目录
cp:拷贝文件
mv:移动文件内容
pwd:显示当前目录
cat:显示文件内容
chmod :改变文件权限
ln:创造文件链接
2.5.(补充任务)将输入的命令写入时间日志
6.将不同文件下的函数建立关联
7.将函数进行封装
目标一的实现:
使用printf函数打印出基础界面,再用getcwd获得本地目录的值,由于值过于长,因此通过while以及if的判断,将打印出来的内容只显示最后一个子目录
其实现子函数如下:
int show(void)
{
char tmp[1024]={0};
char *ptm=NULL;
getcwd(tmp,sizeof(tmp));
ptm=tmp;
while(*ptm !='\0')
{
ptm++;
}
while(*ptm !='/')
{
ptm--;
}
if(strcmp(tmp,"/")!=0)
{
ptm++;
}
printf("[linux@ubuntu:%s]",ptm);
}
目标二的实现:
在主函数中设置一个数组,将其传输到目标二的函数中,用fgets函数将界面上输入的值写入数组中(用stdin),并在数组的最后一项补充‘\0’-----作用为:在目标三中使匹配能够完成。
//主函数中定义数组pcmd(maxlen);
int getuse(char *pcmd,int maxlen)
{
fgets(pcmd,maxlen,stdin);
pcmd[strlen(pcmd)-1]='\0';
}
目标三与四的实现:
将目标二中的数组与预设的命令符号通过strncmp对比,若符合,通过strtok函数对数组中的字符串按空格进行切割,在分别用指针保存切割后的指令,一般第一个指令为命令,后面的指令为输入参数。
int str(char *cmd)
{
if(!strcmp(cmd,"exit"))
{
break;
}
if(!strncmp(cmd,"cd",2))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
cd(token);
}
if(!strncmp(cmd,"cp",2))
{
char *age=NULL;
char *agv=NULL;
char *token=strtok(cmd," ");
age =strtok(NULL," ");
agv =strtok(NULL," ");
cp(age,agv);
}
if(!strncmp(cmd,"chmod",5))
{
char *age=NULL;
char *agv=NULL;
char *token=strtok(cmd," ");
age =strtok(NULL," ");
agv =strtok(NULL," ");
mychmod(age,agv);
}
if(!strncmp(cmd,"ls-l",4))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
lsl(token);
}
if(!strcmp(cmd,"ls"))
{
ls();
}
if(!strncmp(cmd,"ls-a",4))
{
lsa();
}
if(!strncmp(cmd,"mkdir",5))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
mymkdir(token);
}
if(!strncmp(cmd,"rmdir",5))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
myrmdir(token);
}
if(!strncmp(cmd,"ln",2))
{
char *age=NULL;
char *agv=NULL;
char *token=strtok(cmd," ");
age=strtok(NULL," ");
agv=strtok(NULL," ");
ln(age,agv);
}
if(!strncmp(cmd,"mv",2))
{
char *age=NULL;
char *agv=NULL;
char *token=strtok(cmd," ");
age =strtok(NULL," ");
agv =strtok(NULL," ");
mv(age,agv);
}
if(!strncmp(cmd,"touch",5))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
touch(token);
}
if(!strncmp(cmd,"cat",3))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
cat(token);
}
if(!strncmp(cmd,"rm",2))
{
char *token=strtok(cmd," ");
token =strtok(NULL," ");
rm(token);
}
if(!strcmp(cmd,"pwd"))
{
pwd();
}
}
目标五的实现
按照ubantu的shell中的基本功能函数编写函数:
ls功能:先使用getcwd函数获得目录地址,用opendir打开目录,并通过readdir读取目录,当读取到空时停止读取,读取到隐藏目录时,跳过,并将读取到的目录打印出来
#include"head.h"
int ls(void)
{
char *a=NULL;
DIR *b=NULL;
struct dirent *c=NULL;
char *ml=NULL;
a=getcwd(ml,256);
b=opendir(a);
while(1)
{
c=readdir(b);
if(NULL==c)
{
break;
}
if('.'==c->d_name[0])
{
continue;
}
printf(" %s ",c->d_name);
}
printf("\n");
return 0;
}
ls -a功能:将ls的功能删减跳过隐藏文件即可
touch功能:使用fopen函数,打开方式为w即可
#include"head.h"
int touch(char *agv)
{
FILE *a=NULL;
char *p=NULL;
p=agv;
a=fopen(p,"w");
fclose(a);
}
rm功能:使用remove函数
mkdir功能 :使用mkdir函数
rmdir:使用rmdir函数
cd :使用chdir函数
mv:使用rename函数
pwd:使用getcwd函数获得目录并打印
ln:使用link函数链接ab文件
cat:使用r方式打开文件,并将内容存到数组中,使用fputc函数将数组内容打印到终端上
#include"head.h"
int cat(char *q)
{
FILE *tmp=NULL;
char d;
tmp=fopen(q,"r");
while(1)
{
d=fgetc(tmp);
fputc(d,stdout);
if(d==EOF)
{
break;
}
}
printf("\n");
}
chmod :先将从终端输入的字符型数字改变为八进制数字(strtol函数),然后使用chmod函数
#include"head.h"
int mychmod(char *age,char *agv)
{
mode_t mode =0;
mode =strtol(agv,NULL,8);
printf("%d",mode);
chmod(age,mode);
}
cp:将传入的文件用r打开并存到数组中,用w打开传入的目标文件,用fgetc得到数组中的内容,用fputc写入目标文件即可
#include"head.h"
int cp(char *age,char *agv)
{
FILE *tmp=NULL;
FILE *aim=NULL;
char *a=NULL;
char *b=NULL;
a=age;
b=agv;
char c[4096]={0};
char d;
tmp=fopen(a,"r");
aim=fopen(b,"w");
while(1)
{
d=fgetc(tmp);
fputc(d,aim);
if(d==EOF)
{
break;
}
}
}
目标六的实现
1.创造一个包含目标5实现的函数的声明的头文件,并包括各个函数所需的头文件
#ifndef __HEAD_H__
#define __HEAD_H__
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<dirent.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>
#include<stdlib.h>
#include<string.h>
extern int ls(void);
extern int lsa(void);
extern int lsl(const char *agv);
extern int touch(char *agv);
extern int rm(char *agv);
extern int mymkdir(char *agv);
extern int myrmdir(char *agv);
extern int cd(char *agv);
extern int cp(char *age,char *agv);
extern int mv(char *age,char *agv);
extern int pwd(void);
extern int mychmod(char *age,char *agv);
extern int cat(char *q);
extern int ln(char *age,char *agv);
#endif
2.使用Makefile将所有有关文件关联并用make一起编译
OBJ=a.out
OBJT=main.c touch.c cd.c ls-l.c ls.c ls-a.c mkdir.c rmdir.c cat.c rm.c pwd.c cp.c mv.c ln.c chmod.c
$(OBJ):$(OBJT)
gcc $^ -o $@
目标七的实现
用tar -zxvf a.out tar.gz 将a.out压缩,a.out即为应用名,运行文件名可以在Makefile中更改,压缩包就是应用包。
附:目标2.5与主函数
目标2.5:在getuse中使用fopen用w打开一个文件,对文件写入存有输入命令的数组以及输入时间。
int getuse(char *pcmd,int maxlen)
{
FILE *a=NULL;
time_t c;
struct tm *d=NULL;
fgets(pcmd,maxlen,stdin);
pcmd[strlen(pcmd)-1]='\0';
time(&c);
d =localtime(&c);
a=fopen("day.txt","a+");
fprintf(a,"[%04d-%02d-%02d %02d:%02d:%02d]\n",d->tm_year+1900,d->tm_mon+1,d->tm_mday,d->tm_hour,d->tm_min,d->tm_sec);
fwrite(pcmd,25,1,a);
fputc('\n',a);
fclose(a);
}
主函数将getuse、show、str包含即可。