博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现myshell前的准备工作(缕一缕思路)
阅读量:3948 次
发布时间:2019-05-24

本文共 2712 字,大约阅读时间需要 9 分钟。

这篇博客主要讲一下实现myshell前的准备工作

在这里插入图片描述

我们先从基础需求开始

1. 1,2 ,3 要求支持重定向,管道命令以及后台运行,那么首先需要考虑的就是解析参数,输入输出重定向(<,>,>>),管道(|),后台运行(&)与一般命令需要区别开来。

注:>与>> 的区别就是打开文件时的方式不同
fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
fd = open(file,O_RDWR|O_CREAT|O_APPEND,0644);
2. 要实现输入输出重定向的功能就离不开dup() 这个函数。

#include 
int dup(int oldfd); int dup2(int oldfd, int newfd);

dup用来复制 oldfd 所指的文件描述符,当复制成功时,返回最小的尚未被使用的文件描述符。

而dup2与dup的区别就是dup2可以指定新文件描述符。
默认的三个数据流的文件描述符分别为0,1,2,默认的标准输入为终端键盘IO,标准输出和错误输出都是为终端屏幕。
> 以覆盖的方式将屏幕上正确的输出流入到指定的文件或设备上
>> 以追加的方式将屏幕上正确的输出流入到指定的文件或设备上
< 将原本由键盘输入的数据,改由指定的文件内容来替换
3. 实现管道,首先得知道管道是干什么用的?管道简单来说就是让使用者可以同时连续执行命令,但是这是有限制的,管道只能处理前面一个命令传来的正确信息(即标准输出的信息),而且管道必须能使前面传来的数据成为标准输入才能继续执行,还有管道后面的一定要是命令并且还能接受标准输入的数据。了解了管道的定义后,我们来看看应该如何解析执行它,应该以管道为分界线将其划分为两个命令,先执行第一个命令,后等待其进程结束再执行第二个命令。
既然提到等待进程结束我们就来说一说 wait() 这个函数(非常必要的,避免产生僵尸进程)。

#include 
#include
pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options);

wait函数让父进程暂停执行,直到它的一个子进程结束为停止,状态信息将会被写入到statloc。

waitpid 函数也用来等待子进程的结束,但是它可以通过参数 pid 指定要等待的子进程的。
4. 支持后台运行,让父进程直接返回,不等待子进程结束。
5. 如何让命令可以执行,在我们解析判断完之后,我们在 ./, /bin, /usr/bin 这些目录下寻找可执行程序(因为linux的shell上的自带执行程序基本都在这些目录),再寻找到后我们需要通过exec函数族来执行程序

#include 
extern char **environ; int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const envp[]);

使用exec族执行一个可执行的文件来代替当前进程的内存映像。

exec的族的使用并没有产生新的进程,而是把新程序的代码换入,重新分配数据段和栈堆,只保留进程ID。
6. 实现cd,由于cd是shell的内置命令,所以需要我们自己去实现,感觉需要注意的就是 cd 与 cd ~ 都是返回家目录,而 cd - 是返回上一次所在目录(可以定义一个全局字符数组,在切换目录前储存上一次目录所在路径)。
注:基础需求大概就是这些,而界面美观要自己去感受一下,不过可以使用printf() 输出染色试一试

进阶需求

1. tab补全以及历史记录的问题可以通过readline() 这个库函数来解决。

这是ubuntu下的安装代码:

sudo apt-get install libreadline6-dev

注意编译时需要加上 -lreadline

下面给出一段测试代码:

#include 
#include
#include
#include
int main(){
char *buf = NULL; int len; while(1) {
buf = (char *)malloc(sizeof(char) * 256); buf = memset(buf,0,256); buf = readline(""); len = strlen(buf); printf("len = %d buf = %s\n",len,buf); add_history(buf); } return 0;}

而history 命令的实现就是将其储存进所定义的 history 数组前先判断是否与前一条命令相同,不相同再储存。

2. 不能被ctrl + c 打断

signal(SIGINT,SIG_IGN);

SIGINT: 终止进程

3. 设置环境变量这条只需把我们的可执行文件放置在/bin目录即可。

!@#$%^&*~

转载地址:http://jnqwi.baihongyu.com/

你可能感兴趣的文章
成功谈判 你需要几个锦囊?
查看>>
一个人的宽度决定了他的高度
查看>>
善于拜访是另一种经营智慧
查看>>
打造新老员工双赢机制变对立为统一
查看>>
企业如何避免用错人
查看>>
打掉苹果“无与伦比”的傲慢(人民时评)
查看>>
Creating an Android Project
查看>>
Running Your App (android)
查看>>
Starting Another Activity
查看>>
Starting an Activity
查看>>
Stopping and Restarting an Activity
查看>>
Using the Support Library
查看>>
Creating a Fragment
查看>>
Building a Flexible UI
查看>>
Communicating with Other Fragments
查看>>
Saving Key-Value Sets
查看>>
Saving Files
查看>>
Saving Data in SQL Databases
查看>>
Sending the User to Another App
查看>>
Getting a Result from an Activity
查看>>