0. bash原理介绍
bash实际上就是一个负责解析输入字符串工具.
我们需要做的事是这些:
- 手动分割出输入的字符串
- 判断哪些变量是内建命令(自己执行),哪些命令是普通命令(创建子进程执行)
- 实现的功能有: echo export cd 常规指令 输入、输出流重定向
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#define HOST_NAME "hecs-225896"
#define LINE_SIZE 128
#define DELIM " "
#define SHEEL_COMMAND 0
#define NORMAL_COMMAND 1
#define IN_RESTREAM 0
#define OUT_RESTREAM 1
#define APPEND_RESTREAM 2
#define NONE 0
char pwd[LINE_SIZE];
char command[LINE_SIZE];
char* _argv[LINE_SIZE];
char myenv[LINE_SIZE];
int lastcode;
char * filename;
int restream = NONE;
int stream = 0;
char * getpwd()
{
return getcwd(pwd,sizeof(pwd));
}
char* getusr()
{
return getenv("USER");
}
void interactive()
{
char symbol;
if(!strcmp(getenv("USER"),"root"))
symbol='#';
else
symbol='$';
printf("%s@"HOST_NAME":""%s""%c ",getusr(),getpwd(),symbol);
fgets(command,sizeof(command)-1,stdin);
//消除'\n'
command[strlen(command)-1]='\0';
// printf("%s",command);
}
int split()
{
for(int i=0;command[i];i++)
{
if(command[i]=='>') //写入重定向
{
command[i++]='\0';
restream=OUT_RESTREAM;
if(command[i]=='>') //追加重定向
{
restream=APPEND_RESTREAM;
command[i++]='\0';
while(command[i]==' ')i++;
filename=command+i;
printf("filename:%s\n",filename);
stream=open(filename,O_CREAT|O_APPEND,0666);
}
else
{
while(command[i]==' ')i++;
filename=command+i;
printf("filename:%s\n",filename);
stream=open(filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
}
break;
}
else if(command[i]=='<')
{
restream=IN_RESTREAM;
command[i++]='\0';
while(command[i]==' ')i++;
filename=command+i;
printf("filename:%s\n",filename);
stream=open(filename,O_RDONLY);
break;
}
}
int _argc=0;
_argv[_argc++]=strtok(command,DELIM);
while(_argv[_argc]=strtok(NULL,DELIM))
{
_argc++;
}
_argv[_argc]=NULL;
return _argc;
}
int JudgeCommand()
{
if(!strcmp(_argv[0],"cd"))
{
return SHEEL_COMMAND;
}
else if(!strcmp(_argv[0],"echo"))
{
return SHEEL_COMMAND;
}
else if(!strcmp(_argv[0],"export"))
{
return SHEEL_COMMAND;
}
return NORMAL_COMMAND;
}
int execute_NormalCommand()
{
pid_t id=fork();
if(id<0)
{
perror("fork faild\n");
return 1;
}
else if(id==0)
{
if(restream == OUT_RESTREAM || restream == APPEND_RESTREAM )
{
dup2(stream,1);
}
else if(restream == IN_RESTREAM)
{
dup2(stream,0);
}
execvp(_argv[0],_argv);
exit(2);
}
else if(id>0)
{
int status=0;
pid_t wid=waitpid(id,&status,0);
if(wid==id)
lastcode = WEXITSTATUS(status);
}
}
int execute_ShellCommand(int argc)
{
if(argc>=2&&!strcmp(_argv[0],"cd"))
{
int rev=chdir(_argv[1]);
if(rev!=0)
{
perror("return faild");
}
}
else if(argc>=2&&!strcmp(_argv[0],"echo"))
{
if(_argv[1][0]=='$')
{
printf("%c",_argv[1][0]);
char * env=getenv(_argv[1]+1);
if(env)printf("%s\n",env);
}
else if(!strcmp(_argv[1],"?"))
{
printf("%d\n",lastcode);
lastcode=0;
}
else
printf("%s\n",_argv[1]);
}
else if(argc>=2&&!strcmp(_argv[0],"export"))
{
strcpy(myenv,_argv[1]);
putenv(_argv[1]);
}
}
void BuildCommand(int *_argc)
{
if(!strcmp(_argv[0],"ls"))
{
_argv[(*_argc)++]="--color";
_argv[*_argc]=NULL;
}
}
int main()
{
while(1)
{
interactive();
int argc=split();
if(argc==0)continue;
// for(int i=0;i<argc;i++)printf("%s\n",_argv[i]);
int RunFlag=JudgeCommand();
BuildCommand(&argc);
if(RunFlag==NORMAL_COMMAND)
{
execute_NormalCommand();
}
else{
execute_ShellCommand(argc);
}
}
}