Linux简单的shell实现(附源代码)
Linux下Shell的实现说明文档
作业一实验要求:
Shell能够解析的语法为:
commandline := pipecommand | pipecommand "&" commandline | empty
pipecommand := redirectcommand | pipecommand "|" redirectcommand
redirectcommand := command ">" outfile |
command "
command "" outfile |
command ">" outfile "
command
command := program | command argument
需求说明和分析:
本作业要求为实现一个类似于bash的shell。要求支持后台命令,管道,重定向这三个基本功能。并在此基础上,实现一些简单的内部命令,例如cd,pwd等等。
设计方案:
首先利用readline()函数读到用户输入的shell命令,采用一个数组来保存shell命令,数组有固定的大小。
在main()函数中根据字符串中是否存在 "&" 字符判断是否为后台进程。如果是后台命令则判断是否是多条指令,如果不是将分割后的命令传递给pipel()函数,如果是的话分割之后利用while循环将命令传递给pipel()函数。如果不是后台进程,需要用waitpid()函数等待子进程结束后父进程才继续。
在pipel()函数中,将shell命令根据 "|" 字符分割成一个个重定向命令,利用fork ()得到子进程,并完成管道的设置,然后对每个重定向命令调用redirect()函数(如果没有 "|",则将整个shell命令调用redirect()函数)。
在redirect函数里面,根据有没有”>”,”
3、储存结构
1、帮助文档的结构,方便Help命令的构建。
struct HELP_DOC {
char *usage[lengthOfBUILTIN_COMMANDS]; //用法
char *info[lengthOfBUILTIN_COMMANDS]; //介绍
};
2、后台命令管理链表的结构,用于jobs指令的后台储存。
typedef struct BACK_JOBS {
pid_t pid;//记录进程名的pid
char *cmd;
int status;//三种状态 0为DONE 1为RUNNING 2为STOPPED
}BACK_JOB;
3、History命令需要的数据的链表节点结构
typedef struct Node {
int id;
char cmd[100]; //储存每条打过的命令
struct Node *next;
} NODE;
4、shell基本功能的实现难点
1、管道的实现
管道输出核心代码为:
order = trim(strtok(cmd, "|"));
other = trim(strtok(NULL, ""));
if (!other)
redirect(order);
else {
pipe(&fd[0]);
if ((pid = fork()) == 0) {
close(fd[0]);
close(STD_OUT);
dup(fd[1]);
close(fd[1]);
redirect(order);
} else {
close(fd[1]);
close(STD_IN);
dup(fd[0]);
close(fd[0]);
waitpid(pid, &status, 0);
pipel(other);
}}
关闭管道输入端,将标准输出重定向到管道输出,然后关闭管道输出。管道输入的核心代码也是类似的。
输入输出重定向
首先判断是否有输入输出重定向,用标志记录,我把类型分为6种,根据这六种不同的类型,进行不同的重定向的方法。
然后在以下核心代码中实现重定向,即把标准输入输出定向到指定的文件。
if (type == 4 || type == 5 || type == 6) {
if ((fd_out = creat(outfile, 0755)) == -1