#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#define NUM 1024
#define SIZE 32
#define SEP " "
void showEnv()
{
extern char** environ;
int i;
for(i = 0;environ[i];++i)
{
printf("%d:%s\n",i,environ[i]);
}
}
int main()
{
//保存输入的环境变量,防止顶替替换,如果地址变了环境就找不见了
char myenv[32][256];
int env_index = 0;
int last_exit = 0;
while(1)
{
//保存输入后的字符串
char cmd_line[NUM];
//保存打散后的字符串
char *g_argv[SIZE];
//打印出提示信息
while(1)
{
printf("[root@localhost myshell]# ");
//刷新缓冲区
fflush(stdout);
//对cmd_line进程初始化
memset(cmd_line,'\0',sizeof cmd_line);
//获取用户键盘输入
if(fgets(cmd_line,sizeof cmd_line,stdin) == NULL)
{
continue;
//输入错误就重新执行输入操作
}
//因为fgets是读取回车的,所以我们要把字符串的最后一位给去掉
cmd_line[strlen(cmd_line)-1] = '\0';
//这里读取写出来的都是一整串字符串,例如 ls -l -a
// printf("echo: %s\n", cmd_line);
// 那吗如果我们想要执行输入的命令就要对其进行分解
// 分解成:"ls" "-a" "-l"
g_argv[0] = strtok(cmd_line,SEP);//第一次调用的时候,要传入要分解的字符串,第二次调用的时候就可以将要分解的字符串位置写为NULL
int index = 1;
if(strcmp(g_argv[0], "ls") == 0)
{
g_argv[index++] = "--color=auto";
}
if(strcmp(g_argv[0], "ll") == 0)
{
g_argv[0] = "ls";
g_argv[index++] = "-l";
g_argv[index++] = "--color=auto";
}
while(g_argv[index++] = strtok(NULL, SEP));
//因为我们这个原理为子进程替换,所以当执行cd命令的时候,我们就没有办法来返回,或者到达一个位置
//内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
//内建命令本质其实就是shell中的一个函数调用
if(strcmp(g_argv[0],"cd") == 0)
{
if(g_argv[1]!=NULL)chdir(g_argv[1]);
continue;
}
else if(strcmp(g_argv[0],"export") == 0)
{
//我们之前学到的命令几乎都是内建命令
if(g_argv[1] != NULL)
{
strcpy(myenv[env_index],g_argv[1]);
putenv(myenv[env_index++]);
}
continue;
}
else if(strcmp(g_argv[0],"env") == 0)
{
showEnv();
continue;
}
else if(strcmp(g_argv[0],"echo") == 0)
{
const char* target_env = NULL;
if(g_argv[1][0] == '$')
{
if(g_argv[1][1] == '?')
{
printf("%d\n",last_exit);
continue;
}
else
{
target_env = getenv(g_argv[1]+1);
if(target_env != NULL)
printf("%s=%s\n",g_argv[1]+1,target_env);
continue;
}
}
}
//进行进程分割,子进程和父进程
pid_t id = fork();
if(id == 0)
{
//子进程
printf("下面功能是子进程运行的\n");
execvp(g_argv[0],g_argv);
exit(1);
}
else if(id > 0)
{
int statu = 0;
pid_t ret = waitpid(id,&statu,0);
if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(statu));
if(ret > 0){
last_exit = WEXITSTATUS(statu);
printf("exit code: %d\n", WEXITSTATUS(statu));
}
}
}
return 0;
}
【Linux】模拟实现linux的shell
于 2023-08-17 18:08:44 首次发布