Linux 用C语言实现简单的shell(2)
不知不觉两周没有发文了,因为“一万美金的福特奖学金答辩”,ACM比赛,网络论文阅读和网络大作业一大堆事把时间冲散了,所以先写一篇博文补上之前一坑。
之前发了一篇关于linux 用C语言实现简单shell的博文,当时因为刚刚接触linux,只是处理了:
1)外部命令
2)pwd,cd,exit内置命令
3)输入输出重定向
并且代码相比较而言是一步一步添加的,代码相对来讲比较丑QAQ,所以在学完管道之后,相信不得不重新写代码才能实现了。
相比较之前的版本我对代码进行了相关的修改:
1)对于shell指令采用结构体存储,方便管道的切割与执行;
2)采用strtok_r对于指令进行了更加合理的切割;
3)增加了多管道处理;
4)处理了一些简单的异常问题,包括文件路径问题,空行问题,指令错误等。
评论中有朋友想让我加入后台运行‘&’功能的,其实基本上没什么区别,只是对于增加了‘&’后台运行的命令主进程不再需要等待子进程结束再操作了,我已经对我的代码进行了一些修改并加上一定的注释。
/*author:Samsons
date:2015.4.28
1)对于shell指令采用结构体存储,方便管道的切割与执行;
2)采用strtok_r对于指令进行了更加合理的切割;
3)增加了多管道处理;
4)处理了一些简单的异常问题,包括文件路径问题,空行问题,指令错误等。
date:2015.4.30
增加了后台处理命令“&”的处理
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/wait.h> #define MAX 100
#define LEN 100 //shell指令单个管道结构体
struct cmd_list{
int argc; //单个管道参数个数
char *argv[MAX];
}; struct cmd_list *cmdv[MAX]; //shell指令
int num;//shell管道个数
int flagdo;//是否为后台处理命令标记 //执行外部命令
void execute(char *argv[])
{
int error;
error=execvp(argv[],argv);
if (error==-) printf("failed!\n");
exit();
} //切分单个管道
void split_cmd(char *line)
{
struct cmd_list * cmd = (struct cmd_list *)malloc(sizeof(struct cmd_list));
cmdv[num++] = cmd;
cmd->argc = ;
char *save;
char *arg = strtok_r(line, " \t", &save);//切分空格
while (arg)
{
cmd->argv[cmd->argc] = arg;
arg = strtok_r(NULL, " \t", &save);
cmd->argc++;
}
cmd->argv[cmd->argc] = NULL;
} //切分管道
void split_pipe(char *line)
{
char *save;
char * cmd = strtok_r(line, "|", &save);
while (cmd) {
split_cmd(cmd);
cmd = strtok_r(NULL, "|", &save);
}
} //执行管道命令
void do_pipe(int index)
{
if (index == num - )
execute(cmdv[index]->argv);
int fd[];
pipe(fd);//创建管道,0读,1写
if (fork() == )
{
dup2(fd[], );
close(fd[]);
close(fd[]);
execute(cmdv[index]->argv);
}
dup2(fd[], );
close(fd[]);
close(fd[]);
do_pipe(index + );
} //执行内部指令
int inner(char *line)
{
char *save,*tmp[MAX];
char t[LEN],p[LEN];
strcpy(t,line);
char *arg = strtok_r(line, " \t", &save);//切分空格
int i=;
while (arg) {
tmp[i] = arg;
i++;//记录命令个数
arg = strtok_r(NULL, " \t", &save);
}
tmp[i] = NULL;
if (strcmp(tmp[i-],"&")==)//判断是否为后台处理命令
{
flagdo=;
i--;
}
if (strcmp(tmp[],"exit")==)//exit
{
exit();
return ;
}
else
if (strcmp(tmp[],"pwd")==)//pwd
{
char buf[LEN];
getcwd(buf,sizeof(buf));//得到当前路径
printf("Current dir is:%s\n",buf);
return ;
}
else
if (strcmp(tmp[],"cd")==)//cd
{
char buf[LEN];
if (chdir(tmp[])>=)
{
getcwd(buf,sizeof(buf));
printf("Current dir is:%s\n",buf);
}
else
{
printf("Error path!\n");
}
return ;
}
else return ;
} //输入重定向
void cat_in(char *q)
{
char t[];
int fd;
if (q[]=='<')
{
strcpy(t,q+);
fd=open(t,O_RDONLY);
cmdv[]->argv[cmdv[]->argc-]=NULL; //默认重定向为参数的最后一个
cmdv[]->argc--;
if (fd==-)
{
printf("file open failed\n");
return;
}
dup2(fd,);
close(fd);
}
} //输出重定向
void cat_out(char *q)
{
char t[];
int fd;
if (q[]=='>')
{
strcpy(t,q+);
cmdv[num-]->argv[cmdv[num-]->argc-]=NULL;
cmdv[num-]->argc--;
fd=open(t,O_CREAT|O_RDWR,); //0666为权限
if (fd==-)
{
printf("file open failed\n");
return;
}
dup2(fd,);
close(fd);
}
} int main()
{
int i,pid;
char buf[LEN],p[LEN];
while ()
{
fgets(buf,LEN,stdin);//读入shell指令
if (buf[]=='\n') continue;
buf[strlen(buf)-]='\0';
strcpy(p,buf);
int inner_flag;
inner_flag=inner(buf);//内置指令执行
if (inner_flag==)
{
pid=fork();//建立新的进程
if (pid==)
{
split_pipe(p);//管道的切割
//如果是后台处理命令将&符号删除
if (strcmp(cmdv[num-]->argv[cmdv[num-]->argc-],"&")==)
{
cmdv[num-]->argc--;
cmdv[num-]->argv[cmdv[num-]->argc]=NULL;
}
//默认输入输出重定向都是最后一个参数,输入时第一个管道,输出是最后一个管道
if (cmdv[]->argv[cmdv[]->argc-]!=NULL)
{
char q[LEN];
strcpy(q,cmdv[]->argv[cmdv[]->argc-]);
cat_in(q);//输入重定向
}
if (cmdv[num-]->argv[cmdv[num-]->argc-]!=NULL)
{
char q[LEN];
strcpy(q,cmdv[num-]->argv[cmdv[num-]->argc-]);
cat_out(q);//输出重定向
}
do_pipe();//执行管道
exit();
}
if (flagdo==)//非后台处理命令主进程才需等待子进程处理
waitpid(pid,NULL,);
}
}
return ;
}
Linux 用C语言实现简单的shell(2)的更多相关文章
- Linux 用C语言实现简单的shell(1)
发一波福利,操作系统的实验内容,大家可以借鉴一下,不过我的代码可能也存在一定的问题. 因为在一开始老师是一节一节课教的,当时并不知道后面还会用输入输出重定向,管道等一系列问题,我的兴趣也不在这个方面也 ...
- linux下c语言实现简单----线程池
这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...
- 如何在linux下编写一个简单的Shell脚本程序
在了解了linux终端和其搭配的基本Shell(默认为bash)的基础下,我们就可以在终端中用vi/vim编辑器编写一个shell的脚本程序了 Shell既为一种命令解释解释工具,又是一种脚本编程语言 ...
- Linux系统学习笔记之 1 一个简单的shell程序
不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步: ...
- linux 下C语言学习路线
UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...
- Unix和Linux下C语言学习指南
转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...
- Linux学习之路(三)Shell脚本初探
本文参考链接:http://www.runoob.com/linux/linux-shell.html 基本说明 Shell脚本(shell script)是一种为shell编写的脚本程序.其中she ...
- Linux内核分析— —构造一个简单的Linux系统MenuOS(20135213林涵锦)
Linux内核分析— —构造一个简单的Linux系统MenuOS 实验内容 Linux内核的启动过程,从start_kernel到init进程启动 使用实验楼的虚拟机打开shell cd LinuxK ...
- 如何写一个简单的shell
如何写一个简单的shell 看完<UNIX环境高级编程>后我就一直想写一个简单的shell来作为练习,因为有事断断续续的写了好几个月,如今写了差不多来总结一下. 源代码放在了Github: ...
随机推荐
- Python性能(转)
第一部分 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为Python不过是另一门 ...
- 在ajax请求下的缓存机制
1.在服务端加 header(“Cache-Control: no-cache, must-revalidate”);2.在ajax发送请求前加上 anyAjaxObj.setRequestHeade ...
- Java虚拟机组成详解
导读:详细而深入的总结,是对知识“豁然开朗”之后的“刻骨铭心”,想忘记都难. Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我们对jvm有了大体的认识,进入本文之后我 ...
- springmvc的@Validated/@Valid注解使用和BindingResult bindingResult
关于@Valid和Validated的比较 @Valid是使用hibernate validation的时候使用 @Validated 是只用spring Validator 校验机制使用 一:@V ...
- spring mvc: rss(xml)输出
准备: rss包插件 Rome 库及其依赖项rome-utils,jdom和slf4j <!-- rss源依赖 --> <!-- https://mvnrepository.com/ ...
- python脚本10_打印斐波那契数列的第101项
#打印斐波那契数列的第101项 a = 1 b = 1 for count in range(99): a,b = b,a+b else: print(b) 方法2: #打印斐波那契数列的第101项 ...
- jmeter-01 JMeter HTTP测试的各元件功能演示示例
最小的测试将包括测试计划,线程组和一个或多个采样器. Jmeter HTTP测试的各元件演示示例 功能逻辑:wap官网(a.4399sy.com.hk),每个用户登录一次,发帖2次,发帖成功后注销退出 ...
- poj1679次小生成树入门题
次小生成树求法:例如求最小生成树用到了 1.2.4这三条边,总共5条边,那循环3次的时候,每次分别不用1.2.4求得最小生成树的MST,最小的MST即为次小生成树 如下代码maxx即求最小生成树时求得 ...
- spring注入的四种方式
配置文件spring.xml: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=&qu ...
- IOS-APP主流UI框架结构
一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果: 二.搭建过程和注意点 1.新建一个项目,把原有的控制器删 ...