Main.c: 调用Command.c中的函数接口
Terminal.c: 用于实现从终端的接收命令
Command.c: 用于实现将传递进来的命令正确无误的操作进行,如ls,touch,cd, cp等等基本命令
Terminal.h和Command.h: 存放模块头文件
——————————————————————————————————————————
minishell功能
ls -> 查询当前目录文件
ls -a -> 查询当前目录文件包括隐藏文件
ls -l -> 查询当前目录文件详情
ls -l -name -> 查询指定路径的文件详情
touch -> 新建文件
rm -> 删除文件
mkdir -> 新建文件夹
rmdir -> 删除文件夹
cd -> 进入目标文件夹
cp -> 拷贝文件
mv -> 移动/重命名文件
pwd -> 在终端显示当前路径
cat -> 在终端显示文件类型
ln -> 创建文件硬链接
help -> 获取命令使用帮助
***具有终端输入日记记录功能,work.txt文件实时记录终端情况***
——————————————————————————————————————————
代码展示:
head.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
main.c
#include "head.h"
#include "command.h"
int main(int argc, char const *argv[])
{
printf("输入exit后推出minishell\n");
printf("输入help获取命令提示\n");
commands(".");
return 0;
}
Command.h
#ifndef __commands_c__
#define __commands_c__
extern void commands(char *p);
extern void terminal(char *pcomd,char **ppstr,char *pname);
#endif
Command.c
#include "head.h"
#include "terminal.h"
void LS(char *pc)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(pc);
if (NULL == dp)
{
perror("LS- opendir failed\n");
return;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == pp->d_name[0])
{
continue;
}
printf("%s ", pp->d_name);
}
printf("\n");
closedir(dp);
return;
}
void LSa(char *pc)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(pc);
if (NULL == dp)
{
perror("LS-a- opendir failed\n");
return;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
printf("%s ", pp->d_name);
}
closedir(dp);
printf("\n");
return;
}
void LSl(char *pc)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
struct stat buf;
struct passwd *username = NULL;
struct group *gpname = NULL;
struct tm *ptm = NULL;
int ret = 0;
dp = opendir(pc);
if (NULL == dp)
{
perror("fail to opendir\n");
return;
}
while (1)
{
pp = readdir(dp); // 接受返回一个的dirent结构体的指针;
ret = lstat(pp->d_name, &buf); // lstat:从文件名读取文件信息到&buf指向的结构体空间中,失败返回-1,成功返回0;
if (NULL == pp)
{
break;
}
if ('.' == pp->d_name[0])
{
continue;
}
if (-1 == ret)
{
perror("fail to stat\n");
return;
}
// 文件类型判断:
if (S_ISREG(buf.st_mode))
{
printf("-");
}
else if (S_ISLNK(buf.st_mode))
{
printf("l");
}
else if (S_ISBLK(buf.st_mode))
{
printf("b");
}
else if (S_ISSOCK(buf.st_mode))
{
printf("s");
}
else if (S_ISDIR(buf.st_mode))
{
printf("d");
}
else if (S_ISCHR(buf.st_mode))
{
printf("c");
}
else if (S_ISFIFO(buf.st_mode))
{
printf("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(" ");
// 硬链接数目:
printf("%ld ", buf.st_nlink);
// 用户名 组长名:
username = getpwuid(buf.st_uid);
gpname = getgrgid(buf.st_gid);
printf("%s ", username->pw_name);
printf("%s ", gpname->gr_name);
// 字节数
printf("%6ld ", buf.st_size);
// 时间
ptm = localtime(&buf.st_ctime);
printf("%d月 %2d %2d:%2d ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min);
// 文件名
printf("%s ", pp->d_name);
printf("\n");
}
closedir(dp);
return;
}
void LSn(char *pn)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
FILE *fp = NULL;
int ret = 0;
dp = opendir(pn);
if (NULL == dp)
{
fp = fopen(pn,"r");
if (NULL == fp)
{
printf("cannot access '%s':No such file or directory\n",pn);
//perror("");
return;
}
else
{
printf("%s\n", pn);
fclose(fp);
return;
}
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == pp->d_name[0])
{
continue;
}
printf("%s ", pp->d_name);
}
printf("\n");
return;
closedir(dp);
}
void LSln(char *pn)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
struct stat buf;
struct passwd *username = NULL;
struct group *gpname = NULL;
struct tm *ptm = NULL;
int ret = 0;
dp = opendir(pn);
if (NULL == dp) //------------------打开失败则返回pn的文件信息
{
// pp = readdir(dp); // 接受返回一个的dirent结构体的指针;
ret = lstat(pn, &buf); // lstat:从文件名读取文件信息到&buf指向的结构体空间中,失败返回-1,成功返回0;
if (-1 == ret)
{
printf("ls -l '%s' fail to stat: No such file or directory\n",pn);
return;
}
// 文件类型判断:
if (S_ISREG(buf.st_mode))
{
printf("-");
}
else if (S_ISLNK(buf.st_mode))
{
printf("l");
}
else if (S_ISBLK(buf.st_mode))
{
printf("b");
}
else if (S_ISSOCK(buf.st_mode))
{
printf("s");
}
else if (S_ISDIR(buf.st_mode))
{
printf("d");
}
else if (S_ISCHR(buf.st_mode))
{
printf("c");
}
else if (S_ISFIFO(buf.st_mode))
{
printf("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(" ");
// 硬链接数目:
printf("%ld ", buf.st_nlink);
// 用户名 组长名:
username = getpwuid(buf.st_uid);
gpname = getgrgid(buf.st_gid);
printf("%s ", username->pw_name);
printf("%s ", gpname->gr_name);
// 字节数
printf("%6ld ", buf.st_size);
// 时间
ptm = localtime(&buf.st_ctime);
printf("%d月 %2d %2d:%2d ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min);
// 文件名
printf("%s ", pn);
printf("\n");
return;
}
while (1)
{
pp = readdir(dp); // 接受返回一个的dirent结构体的指针;
ret = lstat(pn, &buf); // lstat:从文件名读取文件信息到&buf指向的结构体空间中,失败返回-1,成功返回0;
if (NULL == pp)
{
break;
}
if ('.' == pp->d_name[0])
{
continue;
}
if (-1 == ret)
{
perror("LS-l-n- fail to stat\n");
return;
}
// 文件类型判断:
if (S_ISREG(buf.st_mode))
{
printf("-");
}
else if (S_ISLNK(buf.st_mode))
{
printf("l");
}
else if (S_ISBLK(buf.st_mode))
{
printf("b");
}
else if (S_ISSOCK(buf.st_mode))
{
printf("s");
}
else if (S_ISDIR(buf.st_mode))
{
printf("d");
}
else if (S_ISCHR(buf.st_mode))
{
printf("c");
}
else if (S_ISFIFO(buf.st_mode))
{
printf("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(" ");
// 硬链接数目:
printf("%ld ", buf.st_nlink);
// 用户名 组长名:
username = getpwuid(buf.st_uid);
gpname = getgrgid(buf.st_gid);
printf("%s ", username->pw_name);
printf("%s ", gpname->gr_name);
// 字节数
printf("%6ld ", buf.st_size);
// 时间
ptm = localtime(&buf.st_ctime);
printf("%d月 %2d %2d:%2d ", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min);
// 文件名
printf("%s ", pp->d_name);
printf("\n");
}
closedir(dp);
return;
}
//--------------touch可实现创建文件pn,如果存在则不做改变
void TOUCH(char *pn)
{
FILE *fp = NULL;
fp = fopen(pn, "a");
if (NULL == fp)
{
perror("Touch- fopen failed");
return;
}
fclose(fp);
return;
}
//--------------rm可实现删除文件pn
void RM(char *pn)
{
FILE *fp = NULL;
fp = fopen(pn,"r");
if(NULL == fp)
{
printf("rm: cannot remove '%s': No such file or directory\n",pn);
return;
}
else
{
remove(pn);
fclose(fp);
}
return;
}
//--------------mkdir可实现创建指定路径的文件夹
void MKDIR(char *pn)
{
mkdir(pn, 0777);
return;
}
//--------------rmdir可实现删除指定路径的文件夹
void RMDIR(char *pn)
{
int ret = 0;
ret = rmdir(pn);
if (-1 == ret)
{
printf("RMDIR:failed to REMOVE '%s':Directory not empty\n", pn);
}
return;
}
//--------------cd可实现在转到指定路径
void CD(char *pn)
{
int ret = 0;
ret = chdir(pn);
if (-1 == ret)
{
perror("failed chdir\n");
return;
}
return;
}
//--------------cp可实现在pn1为普通文件的情况下对其进行拷贝
void CP(char *pn1, char *pn2)
{
struct stat buf1;
struct stat buf2;
char tmp[4096] = {0};
int ret1 = 0;
int ret2 = 0;
FILE *fp1 = NULL;
FILE *fp2 = NULL;
DIR *dp2 = NULL;
DIR *dp1 = NULL;
//===============================================================================
// 获取当前的绝对路径
char str[4096] = {0};
getcwd(str, sizeof(str));
//===============================================================================
dp1 = opendir(pn1); //-----------用目录型去打开pn1,如果打开失败则用文件型去打开pn1
if (dp1 == NULL)
{
fp1 = fopen(pn1, "r");
if (NULL == fp1)
{
printf("CP-1- NOT FIND %s\n", pn1); //------------若pn1不存在返回NOT FIND
return;
}
ret1 = lstat(pn1, &buf1);
if (-1 == ret1)
{
perror("CP-1- fail to stat\n");
return;
}
}
//===============================================================================
dp2 = opendir(pn2); //-----------用目录型去打开pn2,如果打开失败则用文件型去打开pn2
if (dp2 == NULL)
{
fp2 = fopen(pn2, "w");
if (NULL == fp2)
{
perror("CP-fp2- open failed\n");
}
ret2 = lstat(pn2, &buf2);
if (-1 == ret2)
{
perror("CP-2- fail to stat\n");
return;
}
if (dp1 == NULL)
{
while (1) //--------------------------复制pn1到pn2的目录下并更名为pn2
{
ret1 = fread(tmp, 1, sizeof(tmp), fp1);
if (0 == ret1)
{
break;
}
fwrite(tmp, 1, ret1, fp2);
}
fclose(fp1);
fclose(fp2);
}
}
else //-----------------------------------------当pn2为路径时,复制pn1到pn2路径下
{
chdir(pn2);
fp2 = fopen(pn1, "w");
while (1)
{
int ret = fread(tmp, 1, sizeof(tmp), fp1);
if (0 == ret)
{
break;
}
fwrite(tmp, 1, ret, fp2);
}
fclose(fp1);
fclose(fp2);
chdir(str);
closedir(dp2);
}
//===========================================================
return;
}
//--------------pwd可获取绝对路径
void PWD(char *pn)
{
char str[4096] = {0};
getcwd(str, sizeof(str));
printf("%s\n", str);
return;
}
//--------------cat可将pn的内容展示到终端
void CAT(char *pn)
{
char str[2048] = {0};
char *pstr = NULL;
FILE *fp = NULL;
fp = fopen(pn, "r");
if (NULL == fp)
{
perror("fopen failed\n");
return;
}
while (1)
{
pstr = fgets(str, sizeof(str), fp);
if (NULL == pstr)
{
break;
}
fputs(str, stdout);
}
fclose(fp);
return;
}
//--------------ln可创造一个硬链接
void LN(char *pn1, char *pn2)
{
FILE *fp = NULL;
fp = fopen (pn2,"r");
if (NULL == fp)
{
link(pn1, pn2);
return;
}
else
{
printf("ln: failed to create hard link '%s': File exists\n",pn2);
}
return;
}
//---------------该函数将当前输入的命令和时间存入到worktime.txt
void WORKTIME(char *pnc, char *pname)
{
FILE *fp = NULL;
struct stat buf;
struct tm *ctime = NULL;
int ret = 0;
int times = 0;
char gctime[256] = {0};
char str[4096] = {0};
getcwd(str, sizeof(str));
chdir("/home/linux/dn/xiangmu");
fp = fopen("worktime.txt", "a");
ret = lstat(str, &buf);
if (-1 == ret)
{
perror("fail to stat\n");
chdir(str);
return;
}
//==================================================================================
//----获取命令并将其传入worktime.txt
ctime = localtime(&buf.st_ctime);
char ntime[256] = {0};
strftime(ntime, sizeof(ntime), "%Y-%m-%d %H:%M:%S", ctime);
fwrite(ntime, strlen(ntime), 1, fp);
fputs(" : ", fp);
fwrite(pname, strlen(pname), 1, fp);
fputs("\n", fp);
fclose(fp);
chdir(str);
return;
}
void commands(char *p)
{
while (1)
{
int i = 0;
char nc[4096] = {0};
char str[4096] = {0};
char hname[32] = {0};
char name[256] = {0};
char *pstr[64] = {0};
struct passwd *username = NULL;
struct stat buf;
lstat(p, &buf);
gethostname(hname, sizeof(hname));
username = getpwuid(buf.st_uid);
getcwd(str, sizeof(str));
printf("%s@%s:%s¥ ", username->pw_name, hname, str); // 显示绝对路径 ----此处应为相对路径
terminal(nc, pstr, name);
WORKTIME(nc, name);
if(NULL == pstr[0])
{
printf("请输入命令:\n");
continue;
}
if (!strcmp(pstr[0], "exit"))
{
break;
}
else if (!strcmp(pstr[0], "ls"))
{
if (NULL == pstr[1])
{
LS(p);
}
else if (!strcmp(pstr[1], "-a"))
{
LSa(p);
}
else if (!strcmp(pstr[1], "-l"))
{
if (NULL == pstr[2])
{
LSl(p);
}
else
{
LSln(pstr[2]);
}
}
else
{
LSn(pstr[1]);
}
}
else if (!strcmp(pstr[0], "touch"))
{
TOUCH(pstr[1]);
}
else if (!strcmp(pstr[0], "rm"))
{
RM(pstr[1]);
}
else if (!strcmp(pstr[0], "mkdir"))
{
MKDIR(pstr[1]);
}
else if (!strcmp(pstr[0], "rmdir"))
{
RMDIR(pstr[1]);
}
else if (!strcmp(pstr[0], "cd"))
{
CD(pstr[1]);
}
else if (!strcmp(pstr[0], "cp"))
{
CP(pstr[1], pstr[2]);
}
else if (!strcmp(pstr[0], "pwd"))
{
PWD(p);
}
else if (!strcmp(pstr[0], "cat"))
{
CAT(pstr[1]);
}
else if (!strcmp(pstr[0], "ln"))
{
LN(pstr[1], pstr[2]);
}
else if (!strcmp(pstr[0],"help"))
{
CAT("help.txt");
}
else
{
printf("输入命令错误!\n");
continue;
}
}
return;
}
terminal.h----------------------------------终端交互模块头文件
#ifndef __terminals_c__
#define __terminals_c__
extern void terminal(char *pcomd,char **ppstr,char *pname);
#endif
terminal.c-----------------------------------终端交互模块
#include "head.h"
void terminal(char *pcomd,char **ppstr,char *pname)
{
int i = 0;
int len = 0;
fgets(pcomd,4096,stdin); //由于此处从输入流接收到额外的'\n'
len = strlen(pcomd);
pcomd[len-1] = '\0'; //所以在此处将'\n'改为'\0'
strcpy(pname,pcomd);
ppstr[0] = strtok(pcomd," ");
//========================================================================
//对接收到的数组以‘ ’为标识进行分割
i = 1;
while(1)
{
ppstr[i] = strtok(NULL," ");
if(NULL == ppstr[i])
{
break;
}
i++;
}
//========================================================================
return;
}
makefile
OBJ:=minishell.out
OBJS+=main.c
OBJS+=command.c
OBJS+=terminal.c
$(OBJ):$(OBJS)
gcc $(OBJS) -o $(OBJ)
.PHONY:
clean:
rm $(OBJ)
install:
sudo cp $(OBJ) /usr/bin
uninstall:
sudo rm /usr/bin/$(OBJ)
memcheck:
valgrind --tool=memcheck --leak-check=full ./$(OBJ)
help-----------------------------------命令提示函数
ls 在终端显示出当前目录下的所有文件
ls -a 在终端显示出当前目录下的所有文件包括隐藏文件
ls -ln 在终端显示出当前目录下的所有文件的详细信息
ls filename 在终端显示filename
ls -l filename 在终端显示filename的详细信息
touch filename 创建一个filename文件
rm filename 删除filename文件
mkdir filename 创建一个filename文件夹
rmdir filename 删除filename文件夹(文件夹需为空)
cd pathname 改变路径为该路径名
cp filename parameter 复制filename文件到参数2下
pwd 在终端显示绝对路径
cat filename 在终端显示filename的内容
ln filename1 filename2 创建一个硬链接,由filename2指向filename1
运行Minishell后显示如下
写在最后:
由于是我第一次创作,很多代码使用不到位,也有冗杂的程序步骤,在我测试过程中存在的bug已经改正,如果有幸被使用,希望得到诸君的指点^_^