目录
一.项目介绍
1.bash介绍
shell是用户和Linux内核交互的接口程序,shell是终端,在提示符输入命令,经过shell 先命令的解释 后传递内核。
bash是shell的一种
2.功能需求及介绍
实现Ubuntu终端及其一些相应的命令
二.代码实现
1.mybash.c
-
这个函数用来实现mybash,可分为三大部分:打印函数、分割函数、命令函数
-
打印函数:打印出如下的功能
-
分割函数:将输入的命令按空格分割,并保存到相应的数组中
-
命令函数:对数组中的命令进行比较,来进行相应的操作,如若输入的是命令,则采用fork+exec,父进程等待,子进程采用exec,调用自己实现的命令文件,进行真实命令的模拟
主函数实现
int main(){
while(1){
//打印函数;
printf_info();
fflush(stdout);
char buff[128]={0};
char* myargv[ARG_MAX] = {0};//ARG_MAX宏定义为10
fgets(buff,127,stdin);
//分割函数
char* cmd = get_cmd(buff,myargv);
if(strncmp(cmd,"exit",4)==0){
break;
}
else if(strncmp(cmd,"\n",1) == 0){
continue;
}
else{
//命令 fork+exec
run_cmd(cmd,myargv);
}
}
exit(0);
}
描述:
大的条件是不断地循环,直至输入相应地命令导致循环退出
1.先通过打印函数打印出相应的信息
2.使用fgets将输入的信息给到buff中
3.使用自定义的get_cmd函数:按空格分割给到myargv数组中,将myargv[0]给到cmd,也就是说cmd存的是输入的第一串字符。
eg:输入 ls -l ,则cmd存的是ls,myargv[0]存的是ls,myargv[1]存的是 -l
4.通过strncmp的比较来进行相应的操作,如若cmd为exit则退出,如遇\n则继续循环,否则调用run_cmd自定义函数,来实现相应的命令
打印函数实现
void printf_info(){
char* user_str = "$";
int user_id = getuid();//获取user 身份id ==0 管理员身份
if(user_id == 0) user_str = "#";
struct passwd* ptr = getpwuid(user_id);
char hostname[128]={0};
gethostname(hostname,128);
char dir[256]={0}; //存储当前位置
getcwd(dir,256);//获取绝对路径
printf("\033[1;32m%s@%s\033[0m:\033[1;34m:%s\033[0m %s ",ptr->pw_name,hostname,dir,user_str);
fflush(stdout);
}
描述:
- 打印函数主要是输出如下的信息及相应的颜色。
- 以下的信息依次为:用户名+‘@’+主机名+‘:’+路径+‘$’/‘#’
-
用户名:通过getpwuid获取结构体指针struct passwd*ptr,然后通过ptr->pw_name来获取用户名
-
主机名:通过gethostname()函数来获取主机名
-
路径:通过getcwd系统调用函数来获取绝对路径
-
字体颜色:通过printf来实现,%s为输出对应的字符串
\033[背景颜色;字体颜色m%s\033[0m
背景颜色:0无设置 1 高亮色
字颜色:30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色
-
“#”/“$”:通过getuid()函数的返回值来判断是用户还是管理员,返回值为0为管理员
分割函数实现
char* get_cmd(char* buff,char* myargv[]){
int len = strlen(buff);
if(buff[len-1] == '\n')
{
buff[len-1] = '\0';
}
char* s = strtok(buff," ");
int i = 0;
while(s != NULL){
myargv[i++] = s;
s = strtok(NULL," ");
}
return myargv[0];
}
这里注意的是buff是输入的一整串字符串,末尾会因fgets的原因带有’\n’(因为fgets是因输入换行符而停止输入的),所以需将最后的’\n’去掉,一面其它命令产生不必要的错误。
分割函数主要是通过strtok函数实现的。这里需要注意的是,在对一个长字符串分割的时候,第一次调用时,strtok函数的第一个参数传入要分割的字符串,而第二次以及后面再次调用该函数的时候,strtok函数的第一个参数应该传入NULL,这是因为在strtok第一个参数为NULL的时候,该函数默认使用上一次未分割完的字符串的未分割的起始位置作为本次分割的起始位置,直到分割结束为止。
run_cmd实现
void run_cmd(char* name,char*myargv[]){
if(name == NULL || myargv == NULL)
return ;
int len = strlen(name);
pid_t pid = fork();
if(pid == -1) return;
if(pid == 0){
char pathname[128] = {0};
if(strncmp(name,"/",1) == 0 || strncmp(name,"./",2) == 0){
strcpy(pathname,name);
}
else{
strcpy(pathname,PATH_BIN);//PATH_BIN为宏定义的文件路径
strcat(pathname,name);
}
execvp(pathname,myargv);
perror("exec err");
exit(0);
}
wait(NULL);
}
描述:
通过fork进程赋值,根据返回的pid的值,父进程等待,子进程使用execvp进行进程替换,将子进程替换为自己写的可执行程序,参数存放在了myargv里。
2.mypwd.c
主要是通过getcwd()函数来实现的,获取绝对路径
int main(){
char path[128]={0};
if(getcwd(path,128) == NULL){
perror("getcwd err");
exit(1);
}
printf("%s\n",path);
exit(0);
}
3.myclear.c
printf(“\033[2J”);//清屏
33[y;xH //设置光标位置
int main(){
printf("\033[2J\033[0;0H");
exit(0);
}
4.mychmod.c
int main(int argc, char*argv[])
{
char* path =argv[2];
int mode = atoi(argv[1]);
int mode_ U = mode/ 100;
int mode_ 9 = (mode-mode_ u*100)/10;
int mode_ 0 = mode%10 ;
mode = mode_ U*8*8 + mode_ g*8 + mode_ 0;
if(chmod( path , mode)==-1)
{
perror( "chmod err" );
exit(1);
}
exit(0);
}
描述:
若使用chmod 则argv[1]为权限数字,argv[2]为路径+文件名,然后使用chmod系统调用函数来实现,值得注意的是argv[2]是八进制的,需转化为10进制。
5.mymkdir.c
主要通过mkdir系统调用函数来实现的
int main(int argc,char*argv[])
{
char*path = argv[1];
int mode=7*8*8+7*8+5;
if(mkdir (path ,mode)==-1)
{
perror("mkdir err");
exit(1);
}
exit(0);
}
6.mycp.c
这里主要通过open与write函数的搭配使用
int main(int argc,char*argv[])
{
char*s_ nameargv[1];
char*s_ newname = argv[2];
int fdw = open(s_ name ,0_ RDONLY,0600);
assert(fdw!=-1);
int fdw2 = open(s_ newname ,0 RDWR |0 CREAT ,0600);
char buff[128]= {0};
int num ;
while(num = read( fdw, buff ,128))
{
write( fdw2,buff,num);
}
close( fdw);
close(fdw2);
exit(0);
}
7.myls.c
int main(int argc ,char *argv[])
{
char buff[128] = {0};
if(strncnp("." ,argv[1],1)== || strncmp ("/" ,argv[1],1)==)
strcpy(buff ,argv[1]);
else
if(getcwd(buff, 128)==NULL) exit(1);
DIR* pdir = opendir(buff);
if(pdir-=NULL) exit(1);
struct dirent* s = NULL ;
while( (s=readdir(pdir))!=NULL)
{
if(strncmp(argv[1],"-a" ,2)==0)
{
struct stat filestat;
stat(s->d_ nane ,&fllestat);
if(S_ ISDIR(filestat.st mode))
printf(" 1033[1;34nxs\033[0m" ,S->d nane);
else
if(filestat.st_ mode & (S_ IXUSR|S_ IXGRPIS. IXOTH))
printf(" 1033[1;32mxs\033[0m",S-xd nane);
else
printf("%s", s->d name);
}
else if(strncmp(argv[1],"-i" ,2)==0)
{
if(strncmp("." s->d nane ,1)==) continue;
struct stat filestat;
stat(s->d_ nane ,&fLestat);
if(5_ ISDIR(filestat.st mode))
printf("%ld 1033[1;34m%s\033[0m" ,5->d ino,s->d nane);
else
if(filestat.st_ mode & (S_ IXUSRIS_ IXGRPIS_ IXOTH))
{
printf("%ld \033[1;327m%s\033[0m" ,s->d. _ino,s->d_ nane);
else
printf("%ld %s ",s->d_ ino,S->d nane);
}
else if(strncmp(argv[1],"-l" ,2)==0)
{
if(strncmp(".",s->d nane,1)==0) continue;
}
else
{
if(strncmp("." ,S->d nane,1)--0) continue;
struct stat filestat;
stat(s->d nane ,&fiLestat);
if(s_ISDIR(filestat.st mode))
printf(" \033[1;34m%s\033[@m” ,s->d. nane);
else
if(filestat.st mode & (S_ IXUSRIS IXGRPIS IXOTH))
printf(”\033[1;32m%s\033[0m” ,s->d. nane);
else
printf("%s " ,s->d nane);
}
}
printf("\n");
closedir(pdir);
exit(0);
}