不知不觉两周没有发文了,因为“一万美金的福特奖学金答辩”,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)的更多相关文章

  1. Linux 用C语言实现简单的shell(1)

    发一波福利,操作系统的实验内容,大家可以借鉴一下,不过我的代码可能也存在一定的问题. 因为在一开始老师是一节一节课教的,当时并不知道后面还会用输入输出重定向,管道等一系列问题,我的兴趣也不在这个方面也 ...

  2. linux下c语言实现简单----线程池

    这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...

  3. 如何在linux下编写一个简单的Shell脚本程序

    在了解了linux终端和其搭配的基本Shell(默认为bash)的基础下,我们就可以在终端中用vi/vim编辑器编写一个shell的脚本程序了 Shell既为一种命令解释解释工具,又是一种脚本编程语言 ...

  4. Linux系统学习笔记之 1 一个简单的shell程序

    不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步: ...

  5. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

  6. Unix和Linux下C语言学习指南

    转自:http://www.linuxdiyf.com/viewarticle.php?id=174074 Unix和Linux下C语言学习指南 引言 尽管 C 语言问世已近 30 年,但它的魅力仍未 ...

  7. Linux学习之路(三)Shell脚本初探

    本文参考链接:http://www.runoob.com/linux/linux-shell.html 基本说明 Shell脚本(shell script)是一种为shell编写的脚本程序.其中she ...

  8. Linux内核分析— —构造一个简单的Linux系统MenuOS(20135213林涵锦)

    Linux内核分析— —构造一个简单的Linux系统MenuOS 实验内容 Linux内核的启动过程,从start_kernel到init进程启动 使用实验楼的虚拟机打开shell cd LinuxK ...

  9. 如何写一个简单的shell

    如何写一个简单的shell 看完<UNIX环境高级编程>后我就一直想写一个简单的shell来作为练习,因为有事断断续续的写了好几个月,如今写了差不多来总结一下. 源代码放在了Github: ...

随机推荐

  1. kylin入门到实战:入门

    版权申明:转载请注明出处.文章来源:http://bigdataer.net/?p=292 排版乱?请移步原文获得更好的阅读体验 1.概述 kylin是一款开源的分布式数据分析工具,基于hadoop之 ...

  2. swoole http_server 多进程并使用多进程处理消息

    <?php $http = new swoole_http_server("0.0.0.0", 9511); $http->set([ 'worker_num' =&g ...

  3. arm-linux-gcc安装使用教程

    arm-linux-gcc如何下载安装2(转) [转]ubuntu下交叉编译环境构建(arm-linux-gcc-3.4.1.tar.bz2 ) 2009-03-03 10:05 1.下载arm-li ...

  4. session判断重复提交

    import javax.servlet.http.HttpServletRequest; /** * @author: jiang * @Date: 2019/2/19 09:37 * @Descr ...

  5. Angular单元测试系列

    Angular单元测试系列 - 大纲Angular单元测试系列 - 简介Angular单元测试系列 - 如何使用Jasmine进行Angular单元测试Angular单元测试系列 - Router.C ...

  6. hand first python 选读(1)

    列表(list) 基本操作 比如说我要整理一个近期热映的电影列表: movies = ["venom", "My Neighbor Totor", " ...

  7. 场景设计以及Manual Scenario和Goal-OrientedScenario的区别

    Manual Scenario 手工场景 主要是设计用户变化,通过手工场景可以帮助我们分析系统的性能瓶颈.手动方案:如果要生成手动方案,请选择此方法.通过创建组并指定脚本.负载生成器和每组中包括的 V ...

  8. 1-16-2 LVM管理和ssm存储管理器使用&磁盘配额

    ssm存储管理器使用&磁盘配额 ssm存储管理器使用 系统存储管理器的使用 系统存储管理器(又称ssm,即system-storage-manager),是RHEL7/CentOS7新增的功能 ...

  9. 026——VUE中事件修饰符之使用$event与$prevent修饰符操作表单

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 决定整理一下canvas的基础学习

    好久没有用过canvas,都要忘完了.还是决定复习一下以前的笔记,以及整理一下笔记,以后好查阅