#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define LEFT "["
#define RIGHT "]"
#define LABLE "$"
#define DELIM " "
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 26
int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];
// 自定义环境变量表
char myenv[LINE_SIZE];
const char* getusername()
{
return getenv("USER");
}
const char* gethostname()
{
return getenv("HOSTNAME");
}
void getpwd()//这里第一版的时候也是直接getenv(“PWD但是由于绝对路径和相对路径的差别我们更改环境变量后路径显示会有问题。
{
getcwd(pwd,sizeof(pwd));
}
void printshell()
{
getpwd();
printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getusername(),gethostname(),pwd);
}
void interact(char *_commandline, int size)
{
char *s = fgets(_commandline, size, stdin);
assert(s);
(void)s;//这里是防止系统认为s没有使用过,出现问题
// "abcd\n\0"
_commandline[strlen(_commandline)-1] = '\0';//\n也会读进去,这里处理一下
}
int splitstring(char _commandline[], char* _argv[])
{
int i = 0 ;
_argv[i++] = strtok(_commandline,DELIM);
while(_argv[i++] = strtok(NULL,DELIM)) ;///strtok第二次以及之后使用,第一个参数都只需要传NULL
return i - 1;
}
int buildCommand(char *_argv[], int _argc)
{
if(_argc == 2 && strcmp(_argv[0],"cd") == 0)
{
chdir(argv[1]);
getpwd();
sprintf(getenv("PWD"),"%s",pwd);
return 1;
}
else if(_argc == 2 && strcmp(_argv[0],"export")== 0)
{
strcpy(myenv,_argv[1]);
putenv(myenv);
return 1;
}
else if(_argc == 2 && strcmp(_argv[0],"echo")== 0)
{
if(strcmp(_argv[1],"$?")==0)
{
printf("%d\n",lastcode);
lastcode = 0;
}
else if(*_argv[1] == '$')
{
char *val = getenv(_argv[1] + 1);
if(val)printf("%s\n",val);
}
else
{
printf("%s\n",_argv[1]);
}
return 1;
}
//特殊处理一下ls,带上颜色
if(strcmp(_argv[0],"ls") == 0)
{
_argv[_argc++] = "--color";
_argv[_argc] = NULL;
}
return 0;
}
void NormalExcute(char *_argv[])
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return;
}
else if(id == 0)
{
execvp(_argv[0],_argv);
exit(EXIT_CODE);//如果成功替换那么就不会执行这条了
}
else
{
int status = 0;
pid_t rid = waitpid(id,&status, 0);
if(rid == id)
{
lastcode = WEXITSTATUS(status);
//接收退出码
}
}
}
int main()
{
while(!quit)
{
//打印命令行
printshell();
//指令交互
interact(commandline,sizeof(commandline));
//分割指令
int argc = splitstring(commandline,argv);
if(argc == 0)continue;//比如我直接输入一个换行符,那就直接进行下一轮判断
//指令判断,如果是内键命令那么由父进程自己来做,不创建子进程如cd
int n = buildCommand(argv, argc);
//普通命令
if(!n)NormalExcute(argv);
}
return 0;
}