【嵌牛导读】shell命令解释器该包含哪些部分
【嵌牛鼻子】shell命令解释器该包含哪些部分
【嵌牛提问】shell命令解释器该包含哪些部分
我们所做的这个简单的shell命令解释器可以实现简单的常用的基本命令,如ls、pwd、cd、cd - 、cd ~ 等
根据简单命令的定义,它的第一个参数是要执行的命令,后面的参数作为该命令的参数。
要执行的命令有两种情况:
一种是外部命令: 也就是对应着磁盘上的某个程序,例如 pwd、ls等等。对于这种外部命令,我们首先要到指定的路径下找到它,然后再执行它。
另一种是内部命令:内部命令并不对应磁盘上的程序,例如cd等等,它需要shell自己来决定该如何执行。例如对 cd 命令,shell就应该根据它后面的参数改变当前路径。
对于外部命令,需要创建一个子进程来执行它,本质就是fork+exec
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <pwd.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX 10
#define STRLEN 128
#define PATH "/bin/" //系统bin路径位置
char OLDPWD[STRLEN]={0}//记录上一次的命令,为了cd -这条命令
//================================================================================
//每次敲回车输出当前所在用户信息
//普通用户和root用户的提示符区别
void Printf_Info()
{
char flag='$'
struct passwd *pw=getpwuid(getuid())
assert(pw!=NULL)
//uid为0则为root用户
if(pw->pw_uid==0)
{
flag='#'
}
struct utsname hostname//主机名
uname(&hostname)
char node[STRLEN]={0}
strcpy(node,hostname.nodename)//获取网络上的名称
char* name=strtok(node,".")
//获取绝对路径
char path[STRLEN]={0}
getcwd(path,STRLEN-1)
char*p=path+strlen(path)//p指向绝对路径的末尾
while(*p!='/')
{
p--
}
//p指向路径末尾往前的第一个‘/’位置处
if(strlen(path)!=1)
{
p++//++前,p->'/'
}
if(strcmp(path,pw->pw_dir)==0)
{
p="~"
}
printf("\033[32mMyBash[%s@%s %s]%c\033[0m",pw->pw_name,name,p,flag)
// \033[4731mThis is a color test\033[0m 设置打印结果的颜色
fflush(stdout)
}
//================================================================================
void Mycd(char*path)
{
//第一个字符串为cd而第二为空 如:cd 则结束本轮循环
if(path==NULL)
{
exit(0)
}
//cd ~ 回到用户根目录
if(strcmp(path,"~")==0)
{
struct passwd*pw=getpwuid(getuid())
path=pw->pw_dir
}
//cd - 回到上一次的位置
if(strcmp(path,"-")==0)
{
//若是第一次输入命令,则cd -命令不存在!
if(strlen(OLDPWD)==0)
{
printf("\033[31mMyBash:cd:OLDPWD not set\n\033[0m")
return
}
//否则把上一次的命令给path
path=OLDPWD
}
//getpwd记录当前工作目录的绝对路径
char oldpwd[STRLEN]={0}
getcwd(oldpwd,STRLEN-1)
if(-1==chdir(path))//反之则不是空,则通过chdir系统调用进入到该目录中
{
char err[128]="\033[31mMybash: cd \033[0m"
strcat(err,path)
perror(err)
}
//每次执行完cd命令后,把工作路径赋给OLDPWD
strcpy(OLDPWD,oldpwd)
}
//================================================================================
//命令分割函数
void Strtok_cmd(char*buff,char*myargv[])
{
char *s=strtok(buff," ")//分割输入的字符串
if(s==NULL) //如果s为空,则进入下一轮循环
{
exit(0)
}
myargv[0]=s//把分割出来的第一个字符串放在myargv[0]中
int i=1
while((s=strtok(NULL,""))!=NULL) //把后续分割出来的字符串依次存放在数组中
{
myargv[i++]=s
}
}
//===============================================================
int main()
{
while(1)
{
char buff[128]={0}
Printf_Info()
//从终端获取命令存入buff中
fgets(buff,128,stdin)
buff[strlen(buff)-1]=0
char *myargv[MAX]={0}
//分割输入的命令
Strtok_cmd(buff,myargv)
//如果输入exit则退出循环
if(strcmp(myargv[0],"exit")==0)
{
exit(0)
}
//如果分割出来的第一个字符串为cd
else if(strcmp(myargv[0],"cd")==0)
{
Mycd(myargv[1])
continue
}
//若是系统调用,直接替换fork+exec
pid_t pid=fork()
assert(pid!=-1)
if(pid==0)
{
char path[256]={0}
if(strncmp(myargv[0],"./",2)!=0 &&strncmp(myargv[0],"/",1)!=0)
{
//先把路径放入path中
strcpy(path,PATH)
}
//进行命令拼接,路径+名称
strcat(path,myargv[0])
//替换进程 例如:/bin/ls
execv(path,myargv)
perror("\033[31mexecv error\033[0m")
}
//处理僵死进程
else
{
wait(NULL)
}
}
}
运行结果如下 :
异常处理如下:
若是第一次运行程序,则不能使用cd - 命令,因为此时还没有历史路径
若进入一个不存在的目录则会报错,没有这个文件或目录
若直接输入一个不存在的无法识别的命令,也会报错。
你是要这几个命令的实现吗?我以前写过一个pwd的。。。你可以看看
其实这都是一些系统调用。。。。。你要搞清楚。。。。好好去看看高编那块内容
以下是pwd命令的实现代码:
伪代码:
pwd
得到.的i-node
得到..的i-node
如果.和..的i-node不同
转到父节点(chdir)
显示父目录的pwd
显示/,加上.对应的目录名(链接名)
(opendir,readdir,closedir)
否则
结束,父目录是/
*/
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
struct dirent *s,*i1,*i2,*i3
DIR *p
while(1){
p=opendir(".")
while( (s=readdir(p))!=NULL){
if((strcmp(".",s->d_name)==0))
i1=s
if((strcmp("..",s->d_name)==0))
i2=s
}
if(i1->d_ino!=i2->d_ino)
{
chdir("..")
p=opendir(".")
while(i3=readdir(p))
{
if(i3->d_ino==i1->d_ino)
printf("/%s",i3->d_name)
}
}
else
{
printf("/")
break
}
}
closedir(p)
printf("\n")
return 0
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)