思路
- 从标准输入当中读取数据(要执行的可执行程序)(fgets)
- 拆分可执行程序名称和命令行参数,标准输入当中读取到的内容第一个空格之前的数据是可执行程序名称,之后都为命令行参数(isspace)
- 创建子进程,子进程程序替换可执行程序(fork)
- 在子进程程序替换时间内,让父进程进行进程等待(execvp、waitpid)
代码实现
minishell.c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
char g_Command[1024];
int GetCommand()
{
memset(g_Command, '\0', sizeof(g_Command));
printf("[minishell@localhost]$ ");
fflush(stdout);
//要从标准输入中去读数据
if(!fgets(g_Command, sizeof(g_Command) - 1, stdin))
{
printf("fgets error\n");
return -1;
}
printf("g_Command = [%s]\n", g_Command);
return 0;
}
int ExecCommand(char* argv[])
{
if(argv[0] == NULL)
{
printf("ExecCommand error\n");
return -1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return -1;
}
else if(pid == 0)
{
//child
execvp(argv[0], argv);
exit(0);
}
else
{
//father
waitpid(pid, NULL, 0);
}
return 0;
}
int DealCommand(char* command)
{
if(!command || *command == '\0')
{
printf("command error\n");
return -1;
}
int argc = 0;
char* argv[32];
//ls -l\n
//argv[0] = "ls"
//argv[1] = "-l"
//var
//strchr(char* str, int c);
//123 456
//char*
//strchr(str, ' ');
while(*command)
{
if(!isspace(*command))
{
argv[argc] = command;
argc++;
while(!isspace(*command) && (*command != '\0'))
{
command++;
}
*command = '\0';
}
command++;
}
//防止一个未定义行为
argv[argc] = NULL;
for(int i = 0; i < argc; i++)
{
printf("[%d][%s]\n", i, argv[i]);
}
ExecCommand(argv);
return 0;
}
int main()
{
while(1)
{
if(GetCommand() == -1)
{
continue;
}
//处理我们所获得的命令
DealCommand(g_Command);
}
return 0;
}
test.c
#include <stdio.h>
#include <unistd.h>
int main()
{
char* argv[3];
argv[0] = "ls";
argv[1] = "-l";
//argv[2] = NULL;
execvp("ls", argv);
printf("hahaha\n");
return 0;
}