不知不觉两周没有发文了,因为“一万美金的福特奖学金答辩”,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. ubuntu16.04后续工作

    一.ruijie https://blog.csdn.net/u012217085/article/details/24369335 https://blog.csdn.net/Lv_Victor/a ...

  2. 从0开始 数据结构 字典树 hdu1251

    字典树 知识补充 '\0'和'\n'的区别 '\0' 是一个字符串的结尾 '\n' 是换行符 gets 和 scanf 的区别 gets()函数总结: gets() 从标准输入设备读取字符串,以回车结 ...

  3. Ubuntu+apache安装redmin

    公司要迁移redmin,本来以为是一个很简单的项目,想不到整整搞了一天加一个晚上. 首先是对ruby的安装不熟悉,现在明白了ruby的安装顺序是先安装rvm版本管理,然后用rvm安装ruby,安装好后 ...

  4. SpringBoot 玩转读写分离

    环境概览 前言介绍 Sharding-JDBC是当当网的一个开源项目,只需引入jar即可轻松实现读写分离与分库分表.与MyCat不同的是,Sharding-JDBC致力于提供轻量级的服务框架,无需额外 ...

  5. 设计模式--模板方法模式C++实现

    模板方法模式C++实现 1定义 定义一个操作的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 实现方案:将算法/逻辑框架放在抽象基类中,并定义好 ...

  6. CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)

    题意 求[X,Y]区间内能被其各位数(除0)均整除的数的个数. CF 55D 有些时候因为问题的一些"整体性"而导致在按位统计的过程中不能顺便计算出某些量,所以只能在枚举到最后一位 ...

  7. 让你的ansible飞起来

    一.SSH Multiplexing 1 配置 vim /etc/ssh/ssh_config Host * GSSAPIAuthentication yes # If this option is ...

  8. guava学习--cache

    转载:http://outofmemory.cn/java/guava/cache/how-to-use-guava-cache   http://www.cnblogs.com/parryyang/ ...

  9. css去掉input记住密码的黄色

    input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autof ...

  10. bzoj1269

    题解: splay维护 只不过变成了字符串 代码: #include<bits/stdc++.h> using namespace std; +,BS= + ,BN= + ; ,head, ...