什么是shell
现在我们使用的操作系统(Windows、Mac OS、Android、iOS等)都是带图形界面的,简单直观,容易上手,对专业用户(程序员、网管等)和普通用户(家庭主妇、老年人等)都非常适用;计算机的普及离不开图形界面。
然而在计算机的早期并没有图形界面,我们只能通过一个一个地命令来控制计算机,这些命令有成百上千之多,且不说记住这些命令非常困难,每天面对没有任何色彩的“黑屏”本身就是一件枯燥的事情;这个时候的计算机还远远谈不上炫酷和普及,只有专业人员才能使用。
对于图形界面,用户点击某个图标就能启动某个程序;对于命令行,用户输入某个程序的名字(可以看做一个命令)就能启动某个程序。这两者的基本过程都是类似的,都需要查找程序在硬盘上的安装位置,然后将它们加载到内存运行。换句话说,图形界面和命令行要达到的目的是一样的,都是让用户控制计算机。然而,真正能够控制计算机硬件(CPU、内存、显示器等)的只有操作系统内核,图形界面和命令行只是架设在用户和内核之间的一座桥梁。
由于安全、复杂、繁琐等原因,用户不能直接接触内核(也没有必要),需要另外再开发一个程序,让用户直接使用这个程序;该程序的作用就是接收用户的操作(点击图标、输入命令),并进行简单的处理,然后再传递给内核。如此一来,用户和内核之间就多了一层“代理”,这层“代理”既简化了用户的操作,也保护了内核。
用户界面和命令行就是这个另外开发的程序,就是这层“代理”。在Linux下,这个命令行程序叫做 Shell。
Linux中的shell,是指一个命令行解释器,表现形式就是一个可以由用户录入的界面,这个界面也可以反馈运行信息。
shell的工作流程
综上,要实现一个迷你shell,必须循环以下步骤:
1.捕捉键盘输入
2.解析输入信息–命令名称、运行参数
3.创建子进程
4.子进程执行对应命令名称的程序(失败必须退出)
5.父进程等待子进程退出
minishell代码
#include<stdio.h> #include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>
int main()
{
while(1)
{
//捕捉键盘输入
printf("[user@host path]$ ");
//fflush(stdout),对标准输出流的清理,但是它并不是把数据丢掉。
//而是及时地打印数据到屏幕上。
//标准输出是以行为单位进行的,也即碰到\n才打印数据到屏幕。
//这就可能造成延时。
fflush(stdout);
char buf[1024]={0};
fgets(buf,1023,stdin);
buf[strlen(buf)-1]='\0';
//解析键盘输入
int myargc = 0;
char* ptr = buf;
char* myargv[64]={NULL};
while(*ptr!='\0')
{
if (*ptr!=' ')
{
myargv[myargc]=ptr;
myargc++;
while(*ptr!='\0'&&*ptr!=' ')
{
ptr++;
}
*ptr='\0';
}
ptr++;
}
myargv[myargc]=NULL;
if(strcmp("cd",myargv[0])==0)
{
chdir(myargv[1]);
continue;
}
//创建子进程
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
continue;
}
else if (pid==0)
{
//子进程执行对于命令名称的程序(程序替换)
execvp(myargv[0],myargv);
perror("execvp error");
exit(-1);
}
//父进程等待
wait(NULL);
}
return 0;
}