打印出提示信息+获取用户键盘输入
cmd_line[NUM];用来保存完整的命令行
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUM 1024
char cmd_line[NUM];
//shell
int main()
{
while(1)
{
printf("[root@localhost myshell]# ");
fflush(stdout);
//sleep(10);
memset(cmd_line,'\0',sizeof cmd_line);
if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
printf("echo: %s\n",cmd_line);
}
}
命令行字符串解析
char *g_argv[SIZE];保存打散后的命令符
strtok第一次调用传入原始字符串,第二次如果还要解析原始字符串则传入空
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define NUM 1024
#define SIZE 32
#define SEP " "
char *g_argv[SIZE];
char cmd_line[NUM];
//shell
int main()
{
while(1)
{
printf("[root@localhost myshell]# ");
fflush(stdout);
//sleep(10);
memset(cmd_line,'\0',sizeof cmd_line);
if(fgets(cmd_line,sizeof cmd_line ,stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
printf("echo: %s\n",cmd_line);
g_argv[0] = strtok(cmd_line,SEP);
int index = 1;
while(g_argv[index++] = strtok(NULL,SEP));
for(index = 0;g_argv[index];index++)
printf("g_argv[%d]:%s\n",index,g_argv[index]);
}
}
加上颜色和部分连续命令
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";
}
TODO内置命令
变化路径
fork()
全部代码
myshell.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define NUM 1024
#define SIZE 32
#define SEP " "
//保存完整的命令行字符串
char cmd_line[NUM];
//保存打散之后的命令行字符串
char *g_argv[SIZE];
// shell 运行原理 : 通过让子进程执行命令,父进程等待&&解析命令
int main()
{
//0. 命令行解释器,一定是一个常驻内存的进程,不退出
while(1)
{
//1. 打印出提示信息 [whb@localhost myshell]#
printf("[root@localhost myshell]# ");
fflush(stdout);
memset(cmd_line, '\0', sizeof cmd_line);
//2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]
if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
{
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
//"ls -a -l -i\n\0"
//printf("echo: %s\n", cmd_line);
//3. 命令行字符串解析:"ls -a -l -i" -> "ls" "-a" "-i"
g_argv[0] = strtok(cmd_line, SEP); //第一次调用,要传入原始字符串
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)); //第二次,如果还要解析原始字符串,传入NULL
//for debug
//for(index = 0; g_argv[index]; index++)
// printf("g_argv[%d]: %s\n", index, g_argv[index]);
//4. TODO,内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令
//内建命令本质其实就是shell中的一个函数调用
if(strcmp(g_argv[0], "cd") == 0) //not child execute, father execute
{
if(g_argv[1] != NULL) chdir(g_argv[1]); //cd path, cd ..
continue;
}
//5. fork()
pid_t id = fork();
if(id == 0) //child
{
printf("下面功能让子进程进行的\n");
//cd cmd , current child path
execvp(g_argv[0], g_argv); // ls -a -l -i
exit(1);
}
//father
int status = 0;
pid_t ret = waitpid(id, &status, 0);
if(ret > 0) printf("exit code: %d\n", WEXITSTATUS(status));
}
}
Makefile
```cpp
myshell:myshell.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f myshell