shell:命令行解释器,捕捉用户输入,根据输入的信息运行指定的命令程序。
利用进程终止,等待,替换既可以完成简单的minishell,我们分析一下shell的功能就是捕捉用户输入,对用户输入进行处理,进行程序替换,进程等待防止出现僵尸进程。
1. 捕捉用户输入
捕捉输入吗scanf_s就好了呀,不行!scanf_s遇到空格就停止了,gest(char * buf);从标准输入读取一行数据" pwd ..";
2.字符串解析
得到命令名称和运行参数” pwd .. “ 把他放到argv数组里面去
3.创建子进程
创建子进程给子进程进行程序替换,并设置运行参数 因为是bin目录下的那些程序所以选择esec函数簇里面的execvp(argv[ 0 ],argv)
不能直接对shell进行替换,因为替换后运行完新的程序进程就退出了,如果替换了shell,shell运行完就会退出,万一要是运行的指令崩溃了shell也就崩溃了,因此要创建子进程让子进程运行指令
我们来看看为啥替换完新的进程原先进程就退出了
这里实现两端代码
example:
#include<stdio.h>
//程序是有运行参数和环境变量的
//程序的运行参数在给予的时候是运行程序一空格间隔跟在程序之后的
//程序的运行参数,就会被保存在argc这个字符数组中
//程序的环境变量,就会保存在env这个字符数组中,或者有个全局变量environ
int main(int argc, char *argv[], char *env[])
{
extern char **environ;
printf("程序参数个数: %d \n",argc);
printf("程序运行参数: \n");
for(int i = 0;argv[i] != NULL;i++)
{
printf("\t %s \n",argv[i]);
}
printf("程序的环境变量: \n");
for(int i = 0;environ[i] != NULL;i++)
{
printf("\t %s \n",environ[i]);
}
return 0;
}
和一段exec.c来验证
#include<unistd.h>
#include<stdio.h>
int main()
{
extern char **environ;
printf("hello !\n ");
char *argv [] = {"./example" ,"-a" , "-l" , "-c", NULL };
execve("./example", argv, environ);//程序替换
printf("can you see me ?");
}
我们能看见can you see me ? 吗
是看不见的 ,所以是为啥要fork一个子进程
4.进程等待
防止子进程运行完指令退出后成为僵尸进程
5.代码实现
int main()
{
while(1)
{
//字符串捕捉
printf("[username@hostname]$ ");
fflush(stdout);
char input[1024] = {0};
fgets(input,1023,stdin);
input[strlen(input) - 1] = '\0';
printf("[%s]\n",input);
//字符串解析(把指令能拿出来)
char *ptr = input;
char *argv[32] = {NULL};
int argc = 0;
while(*ptr != '\0')
{
if(*ptr == ' ')
{
ptr++;
continue;
}
argv[argc] = ptr;
argc++;
while(*ptr != '\0' && *ptr != ' ')
{
ptr++;
}
*ptr = '\0';
ptr++;
}
argv[argc] = NULL;
for(int i = 0;argv[i] != NULL;i++)
{
printf("[%s]\n",argv[i]);
}
//子进程替换
int pid = fork();
if(pid == 0)
{
execvp(argv[0],argv);
exit(-1);//替换失败就退出不要接管成第二个shell
}
wait(NULL);//进程等待
}
return 0;
}
结果展示
应用进程控制实现简单的shell