minishell全过程
程序员文章站
2022-07-10 15:41:50
...
#include <stdio.h>
#include <unistd.h>
void show()//程序开始输出与shell一样的命令行
{
char path[256]={0};/创建buf存储当前路径
getcwd(path,sizeof(path));//调用getcwd获得当前路径
printf("[email protected]:%s$ ",path);//存放在缓存区
fflush(stdout); //立即输出缓存区
}
开始界面的设置
总体的所有文件
难点在于对于输入命令的解析,判断。mmmm
#include <string.h>
#include <stdio.h>
#include "show.h"//前面所设置的显示界面头文件
#include "docmd.h"//后面执行命令的头文件
int proccmd()//命令解释函数
{
char cmd[512]={0};//存储用户输入的命令
char* arg[4]={0};//定义指针数组,先分析命令最长不超过四个,所以定义四个指针
while(1)
{
show();
fgets(cmd,sizeof(cmd),stdin);//输入命令比如ls 敲\n
cmd[strlen(cmd)-1]='\0';//去掉\n
arg[0]=strtok(cmd," ");//用strtok函数将输入的命令用空格断开
if(NULL == arg[0])
{
continue;//这是判断如果用户输入的是空格那么跳过此次循环从新开始下一次,相当于又把命
//令行输出一边
}
else
{
break;//如果命令不为空跳出while循环
}
}
arg[1]=strtok(NULL," ");//分别让剩下的三个指针指向分割下来的命令
arg[2]=strtok(NULL," ");
arg[3]=strtok(NULL," ");
int ret = docmd(arg);//调用执行命令函数并且接收一下执行命令函数的返回值,判断是否成功
return ret;
}
命令分解(解释函数)
#include <string.h>
#include "mingling.h"
#include "ll.h"//写的ll命令的头文件
#include "cat.h"//cat头文件
#include "ln.h"
#include "touch.h"//各种命令的头文件
#include "rm.h"
#include "mv.h"
int docmd(char* arg[4])//传入刚才的指针数组
{
if(0 == strcmp("ls", arg[0]))//因为是字符串所以用strcmp比较
{
dols(arg);//ls ls/etc。ls有两种可能
}
else if(0 == strcmp("cp", arg[0]))//cp命令
{
docp(arg);//ls ls/etc
}
else if(0 == strcmp("cd", arg[0]))
{
docd(arg);//ls ls/etc
}
else if(0 == strcmp("quit",arg[0]))//退出程序命令
{
return 1;//返回1程序结束,其他成功返回0
}
else if(0 == strcmp("ll",arg[0]))
{
doll(arg);
}
else if(0 == strcmp("cat",arg[0]))
{
docat(arg);
}
else if(0 == strcmp("ln",arg[0]))
{
doln(arg);
}
else if(0 == strcmp("touch",arg[0]))
{
dotouch(arg);
}
else if(0 == strcmp("mv",arg[0]))
{
domv(arg);
}
else if(0 == strcmp("rm",arg[0]))
{
dorm(arg);
}
return 0;
}
各种命令调用函数,这里我大概写了11个命令,ls,cp,ll,touch,mv等......
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
int Mystat(char *filename)
{
struct stat st;
int ret = stat(filename,&st);
if(-1 == ret)
{
printf("stat error\n");
return -1;
}
if(S_ISREG(st.st_mode))
{
fputc('-',stdout);
}
else if(S_ISDIR(st.st_mode))
{
fputc('d',stdout);
}
else if(S_ISCHR(st.st_mode))
{
fputc('c',stdout);
}
else if(S_ISBLK(st.st_mode))
{
fputc('b',stdout);
}
else if(S_ISFIFO(st.st_mode))
{
fputc('p',stdout);
}
else if(S_ISLNK(st.st_mode))
{
fputc('l',stdout);
}
else if(S_ISSOCK(st.st_mode))
{
fputc('s',stdout);
}
if(st.st_mode &S_IRUSR )
{
fputc('r',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IWUSR )
{
fputc('w',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IXUSR )
{
fputc('x',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IRGRP )
{
fputc('r',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IWGRP )
{
fputc('w',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IXGRP )
{
fputc('x',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IROTH )
{
fputc('r',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IWOTH )
{
fputc('w',stdout);
}
else
{
fputc('-',stdout);
}
if(st.st_mode &S_IXOTH )
{
fputc('x',stdout);
}
else
{
fputc('-',stdout);
}
struct tm *tm_info = localtime(&st.st_mtime);//获取当地时间
uid_t uid =1000;
struct passwd * pw = getpwuid(uid);
if(NULL == pw)
{
printf("getpwuid error\n");
return 1;
}
gid_t gid =1000;//获得linux用户名,不然只是id号1000,与系统不一致
struct group * gr = getgrgid(gid);
if(NULL == gr)
{
printf("getgrgid error\n");
return 1;
}
//仿照linux的ll输出样板,进行输出
printf(" %lu %s %s %lu %4d-%02d-%02d %02d:%02d:%02d %s\n",st.st_nlink,
pw->pw_name,gr->gr_name,st.st_size,tm_info->tm_year+1900,tm_info->tm_mon+1,tm_info->tm_mday
,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec,filename);
return 0;
}
int doll(char *arg[])//命令名,命令的具体函数
{
DIR *dir;
if(NULL != arg[1])
{
dir = opendir(arg[1]);//判断是不是当前路径,不是就切换
chdir(arg[1]);
}
else
{
dir = opendir("./");//如果后面不跟参数默认为当前路径
}
if(NULL == dir)
{
printf("opendir erreor\n");//空就为打开失败
return -1;
}
while(1)
{
struct dirent *info = readdir(dir);//读取目录
if(NULL == info)
{
break;
}
Mystat(info->d_name);
}
closedir(dir);//不能忘记关闭目录
printf("目录详细信息,如上^\n");//这个是我自己加的一个输出显示
return 0;
}
这是ll命令的.c函数
#ifndef __LL_H__//判断是否已经进行过声明,如果没有就声明,有就不声明了
#define __LL_H__
extern int doll(char *arg[]); //定义一个外部的函数
#endif
这是ll命令的.h文件
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include "mingling.h"
int dols(char* arg[])
{
// ls ls /etc
int i = -1;
DIR* dir =NULL;
if(NULL == arg[1])
{
dir =opendir("./");
}
else
{
dir =opendir(arg[1]);
}
if(NULL == dir)
{
printf("打开目录失败\n");
return 1;
}
while(1)
{
struct dirent * info = readdir(dir);
if(NULL == info)
{
break;
}
i++;
if(0 == i%8)
{
printf("\n");
}
printf("%-12s ",info->d_name);
}
closedir(dir);
printf("\n");
printf("目录展开成功,如上^\n");
return 0;
}
int docp(char* arg[])
{
// cp 1 2
int srcfd = open(arg[1],O_RDONLY);
int dstfd = open(arg[2],O_WRONLY|O_CREAT|O_TRUNC,0666);
if(-1 ==srcfd || -1 == dstfd)
{
printf("open error\n");
return 1;
}
char buf[1024]={0};
while(1)
{
int rd_ret = read(srcfd,buf,sizeof(buf));
if(rd_ret<=0)
{
break;
}
write(dstfd,buf,rd_ret);
}
close(srcfd);
close(dstfd);
printf("文件复制成功\n");
printf("%s-->%s\n",arg[1],arg[2]);
return 0;
}
int docd(char* arg[])
{
//cd cd /etc
if(NULL == arg[1])
{
chdir("/home/linux");
printf("成功进入到家目录\n");
}
else
{
int ret = chdir(arg[1]);
if(-1 == ret)
{
perror("chdir");
}
printf("成功进入到%s\n",arg[1]);
}
return 0;
}
这段代码实现了ls,cd,cp,这是.c文件
#ifndef __MINGLING_H__
#define __MINGLING_H__
extern int dols(char* arg[]);
extern int docp(char* arg[]);
extern int docd(char* arg[]);
#endif
这是ls,cd,cp的.h文件
#include <stdio.h>
int docat(char *arg[])
{
FILE *fp = fopen(arg[1], "r");
if (NULL == fp)
{
printf("fail to fopen\n");
return -1;
}
while (1)
{
int ch = fgetc(fp);
if (EOF == ch)
{
if (feof(fp))
{
break;
}
else if (ferror(fp))
{
printf("fgetc error\n");
return -1;
}
}
fputc(ch, stdout);
}
printf("文件详细信息如上^\n");
fclose(fp);
return 0;
}
这是cat.c
声明就和之前ll.h一样
其他的就比较简单不一一说明了,如有需要请留言
上一篇: CentOS7.4下安装ceph
下一篇: HTTP协议笔记