编写一个minishell
什么是shell
Shell是Linux系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。是在Linux内核与用户之间的解释器程序,现在Linux通常指/bin/bash解释器来负责向内核翻译以及传达用户/程序指令,shell相当于操作系统的“外壳”
shell都做了什么工作
当我们通过认证进入到Linux系统当中后,操作系统会帮我们运行一个进程-bash , 我们登录后看到的界面就是shell进程,shell会捕获用户的输入命令,并对这些命令进行解析,解析之后就会创建子进程去处理这些命令,执行完毕后shell会再次回到捕获命令的状态,等待用户的再次输入。
模拟实现一个mini的shell程序
- 首先,我们要打印一个提示符一直处于一行的前面,显示当前用户名主机目录等信息,我们这里偷了个懒,直接打印字符串,显示到屏幕。
- 接着就是获取用户的输入字符串,把输入的字符串保存到一个字符数组里。
- 然后对这个字符数组进行解析,把命令用分隔符" "拆分开来,保存到指针数组里,完成字符串的解析。
- 接着创建一个子进程,对子进程进行程序替换,让子进程执行相应的命令。
- 父进程的任务是等待子进程的退出,并判断子进程的退出状态信息,也就是指令的执行情况,并对子进程进行资源回收。
- 最后就是回到第一步再次循环捕获输入的命令。
完整代码实现
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#define SIZE 256
#define NUM 16
int main() {
//命令字符串
char cmd[SIZE];
//提示符
const char* cmd_line = "[minishell@CentOS]$";
//shell循环读取命令执行
while (1) {
//初始化获取到的命令字符串
cmd[0] = 0;
//让提示符一直打印到前面
printf("%s", cmd_line);
//捕获输入的命令到cmd里
fgets(cmd, SIZE, stdin);
//获取到的命令字符串最后一个\n去掉
cmd[strlen(cmd) - 1] = '\0';
//定义指针数组用来保存解析后的字符串
char* args[NUM];
/
//解析命令字符串
args[0] = strtok(cmd, " ");
int i = 1;
do {
args[i] = strtok(NULL, " ");
if (args[i] == NULL) {
break;
}
++i;
} while (1);
//
//字符串解析完毕
//
//创建子进程并对命令进行处理
pid_t id = fork();
if (id < 0) {
perror("fork error!\n");
continue;
}
if (id == 0) {
//child
//子进程内调用进程替换函数
execvp(args[0], args);
exit(1);
}
//父进程等待子进程处理
int st;
pid_t ret = waitpid(id, &st, 0);
if (WIFEXITED(st) && ret == id) {
if (WEXITSTATUS(st) == 1) {
printf("-bash: %s: command not found\n", args[0]);
}
}
}
return 0;
}
通过对这个shell进行测试,可以运行很多常用的命令,但是和真实的shell还有很多差距,也有很多管道或者重定向等命令不能执行。