之前已经花了不少篇幅学习了linux系统编程的很多知识点:文件与io、进程、信号、管道,而零散的知识点,怎么能够综合的串接起来是学习的一个很重要的目的,当然最好的方式就是用所学的知识点做一个项目了,所以接下来会实现一个小型的迷你shell程序,跟缩减版的系统shell程序,不要看着项目很小,但是五脏俱全,先来看一下我们要实现的功能:
![](https://i-blog.csdnimg.cn/blog_migrate/8cce1e43e7bdf5130961575417c3af6c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f85b6eecee82bc0350392d3951f7ee01.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9b00814b153883428aa3e88e0da862e6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/98854bf761a734d72d9293b557a99deb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9c12024e36db7a0d87b733fa89d44e8c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fe9b475bed440cd78649f64264b251cf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ba63f48a1160d1135f788b20a6cfc6de.png)
![](https://i-blog.csdnimg.cn/blog_migrate/aafa214e35ba3bd85aaedf4dff9b6fd0.png)
如exit会退出程序等。
![](https://i-blog.csdnimg.cn/blog_migrate/59886c0d740c62c7e2ca4a2b8f864a01.png)
另外还能捕捉一些信号,如:ctrl+c,也能忽略一些信号,如:ctrl+\,禁止退出自己的程序,这里就不演示了。
下面就来从零开始一步步实现我们自己的shell程序,首先进行模块的划分:
-------main.c //这个是一个主控程序
-------parse.c、parse.h //这个主要是用来进行shell命令的解析的
![](https://i-blog.csdnimg.cn/blog_migrate/c1f99a285fba4a7ad1406169b3b0cee4.png)
再编写一个Makefile,由于项目中会由多个.c文件构成,所以很有必要进行整体编译,关于Makefile的写法,可以参考博文:http://www.cnblogs.com/webor2006/p/3789589.html
![](https://i-blog.csdnimg.cn/blog_migrate/b55957fad65910de40b0499fc652fe5b.png)
这个Makefile的编写是比较简单的,这里就不详述了,里面内容如下:
![](https://i-blog.csdnimg.cn/blog_migrate/168ec64dda1f0a64f1dc55608174723f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/377464b569acd8e6441b48a2bc5d668f.png)
这样,总体的项目编译环境就已经搭建好了,另外说明一下实现的思路:先搭建好一个整体的框架,然后于对其每个模块进行一一细化,最终完善整个功能,所有功能的实现都会按这个思路来,而且很重要的一条就是:步步为营,也就是当写完一段代码后,就立马进行编译运行,来确保每小段代码都成功,这样的话,一点点功能进行拆分,最终实现一个项目,所以接下来,先要实现一个简单的框架功能:
![](https://i-blog.csdnimg.cn/blog_migrate/92ccea4d2d3966fb3e9cfc1b3c219c0e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fce73bac87d855a257038cb344fe2ab6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/64a07012d6564c0f28cb2db9ae9f1e4d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6ef727166e689e993fb82046f24759e3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5e652d9864389e045faa53b327d2a035.png)
![](https://i-blog.csdnimg.cn/blog_migrate/673b6f0fb7a6c8e503fb865ac344c00b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5b0c5f2be585d80181ba2b7c1ddfad4f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f815ebe08a3c74a8cd36290d39e8de36.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f82ceea7176008e9634296c7678ff170.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f4101dbce563db1c2f7430023be2e63b.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6b61d00abae458527c2d7898b293790a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/72839f0e153aadf53fe5b6b44ff950af.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6778e7337d9fab10952c1c2b5d52565a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/19f9c6ca94c386b5c1685be0bbc7028f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e824e76a2bae59784e93b167bea61ee2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e391c4d8ca90e0588e8a6deb6c41b0a1.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1e5fc17418ad44b9d4bd436b03319ff2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1e60682a48061f339cf41b55038e5318.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e880adfdb6dc22e7ecb686e3c6622167.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a853cbe8970d7b9ac5aaa576e425f265.png)
![](https://i-blog.csdnimg.cn/blog_migrate/db47ff254acce9a5a45c5b037f920623.png)
![](https://i-blog.csdnimg.cn/blog_migrate/39b3a8adb87291c92cf6b3392c78bf02.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4868121907fab9ea3f31e364ef2b42f1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/98a1b702d670aae90c37d5a74a3c5eb4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f3e6aae74d3b3856f1e3142659f5e1ef.png)
![](https://i-blog.csdnimg.cn/blog_migrate/182fba56da75e92e73eb562e96dcedda.png)
![](https://i-blog.csdnimg.cn/blog_migrate/da32d07a11f3cea07568d7a8f0a9fe19.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4c8b87bbe71b5ac3f0d1d79ea24896bd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1d9d2873a8fb0fccd149ea11116ba81a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c9c4389bfcf26d321c88b792408add85.png)
![](https://i-blog.csdnimg.cn/blog_migrate/53930c5ec36bd2a0a027af7d22a69733.png)
![](https://i-blog.csdnimg.cn/blog_migrate/da92f66849c58fdfb40ccb5031344142.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cab714f8756b89b39e7c11d30a5b2231.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9cdb2683bf7bb7a078652ff8e683bdac.png)
![](https://i-blog.csdnimg.cn/blog_migrate/80e4eb2ec101a1cfa7766263bd77fedf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/40841f1e3e24451368e309763ff5e833.png)
![](https://i-blog.csdnimg.cn/blog_migrate/51c2c53730a20659051b6fc7f289dcb2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/df494e0f11151a52eb19af995b376199.png)
![](https://i-blog.csdnimg.cn/blog_migrate/350f4de934d53879f6c97e4ec0819c16.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6c8b5d6216aab25a7ee9fb604d5eafd5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/20e2152723cd3cbd01926b713bd9b6fc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dfb0805405c339db76058904ce3bc161.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2bbc21ef1da44ee116f1bfe6262de336.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7d56a6275385243a0294e0713734a4e9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3c8fad2fc73122daae92da6c2b609eb6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/68c6710768d368114e08b40c49d07514.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d20dc2494de0978116ddfa9477a28dc5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9e884ffae1791075a83f4a054955f842.png)
![](https://i-blog.csdnimg.cn/blog_migrate/81b611e557f18a9be9f3b61dbf197361.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bac6f77a5b7c6fa1446a1a2bc4dccd90.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3da78288e6b895a6b83bb6651ad8c52a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a8560d85c76ad03841c7b20c9a90f967.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c897b9d9b28a38ba049ef60e9781d8a1.png)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "parse.h"
#include "externs.h"
#include "init.h"
/*
* shell主循环
*/
void shell_loop(void){
while(1){
printf("[myshell]$ ");
fflush(stdout);
/* 初始化环境 */
init();
if(read_command() == -1)
break;
parse_command();
execute_command();
}
printf("\nexit\n");
}
/*
* 读取命令
* 成功返回0,失败或者读取到文件结束符(EOF)返回-1
*/
int read_command(void){
if(fgets(cmdline,MAXLINE,stdin) == NULL){
return -1;
}
return 0;
}
/*
* 解析命令
* 成功返回解析到的命令个数,失败返回-1
*/
int parse_command(void){
char *cp = cmdline;
char *avp = avline;
int i = 0;
while(*cp != '\0'){
/** 去除左空格 **/
while(*cp == ' ' || *cp == '\t')
cp++;
/* 如果到了行尾,跳出循环 */
if(*cp == '\0' || *cp == '\n')
break;
cmd.args[i] = avp;
while (*cp != '\0'
&& *cp != ' '
&& *cp != '\t'
&& *cp != '\n')
*avp++ = *cp++;
//printf("[%s]\n",cmd.args[i]);
*avp++ = '\0';
i++;
}
return 0;
}
/*
* 执行命令
* 成功返回0,失败返回-1
*/
int execute_command(void){
pid_t pid = fork();
if(pid == -1){
//进程创建失败
ERR_EXIT("fork");
}
if(pid == 0) {
//子进程去执行替换函数
execvp(cmd.args[0],cmd.args);
}
//父进程等待子进程的退出,这样并不会改变父进程本身的行为,所以进程就不会退出了
wait(NULL);
return 0;
}
这节的最终运行效果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/a9405c1446ece11e112192505a3b953a.gif)