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)处理了一些简单的异常问题,包括文件路径问题,空行问题,指令错误等。
  */
#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管道个数

//执行外部命令
void execute(char *argv[])
{
        int error;
        error=execvp(argv[0],argv);
        if (error==-1)  printf("failed!\n");
        exit(1);
}

//切分单个管道
void split_cmd(char *line)
{
     struct cmd_list * cmd = (struct cmd_list *)malloc(sizeof(struct cmd_list));
     cmdv[num++] = cmd;
     cmd->argc = 0;
     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 - 1)
        execute(cmdv[index]->argv);
    int fd[2];
    pipe(fd);//创建管道,0读,1写
    if (fork() == 0)
    {
        dup2(fd[1], 1);
        close(fd[0]);
        close(fd[1]);
        execute(cmdv[index]->argv);
    }
    dup2(fd[0], 0);
    close(fd[0]);
    close(fd[1]);
    do_pipe(index + 1);
}

//执行内部指令
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=0;
    while (arg) {
        tmp[i] = arg;
        i++;//记录命令个数
        arg = strtok_r(NULL, " \t", &save);
     }
    tmp[i] = NULL;
    if (strcmp(tmp[0],"exit")==0)//exit
    {
        exit(0);
        return 1;
    }
    else
    if (strcmp(tmp[0],"pwd")==0)//pwd
    {
        char buf[LEN];
        getcwd(buf,sizeof(buf));//得到当前路径
        printf("Current dir is:%s\n",buf);
        return 1;
    }
    else
    if (strcmp(tmp[0],"cd")==0)//cd
    {
        char buf[LEN];
        if (chdir(tmp[1])>=0)
        {
            getcwd(buf,sizeof(buf));
            printf("Current dir is:%s\n",buf);
        }
        else
        {
            printf("Error path!\n");
        }
        return 1;
    }
    else return 0;
}

//输入重定向
void cat_in(char *q)
{
    char t[30];
    int fd;
    if (q[0]==‘<‘)
    {
        strcpy(t,q+1);
        fd=open(t,O_RDONLY);
        cmdv[0]->argv[cmdv[0]->argc-1]=NULL;  //默认重定向为参数的最后一个
        cmdv[0]->argc--;
        if (fd==-1)
        {
            printf("file open failed\n");
            return;
        }
        dup2(fd,0);
        close(fd);
    }
}

//输出重定向
void cat_out(char *q)
{
    char t[30];
    int fd;
    if (q[0]==‘>‘)
    {
        strcpy(t,q+1);
        cmdv[num-1]->argv[cmdv[num-1]->argc-1]=NULL;
        cmdv[num-1]->argc--;
        fd=open(t,O_CREAT|O_RDWR,0666); //0666为权限
        if (fd==-1)
        {
            printf("file open failed\n");
            return;
        }
        dup2(fd,1);
        close(fd);
    }
}

int main()
{
    int i,pid;
    char buf[LEN],p[LEN];
    while (1)
    {
        fgets(buf,LEN,stdin);//读入shell指令
        if (buf[0]==‘\n‘) continue;
        buf[strlen(buf)-1]=‘\0‘;
        strcpy(p,buf);
        int inner_flag;
        inner_flag=inner(buf);//内置指令执行
        if (inner_flag==0)
        {
            pid=fork();//建立新的进程
            if (pid==0)
            {
                split_pipe(p);//管道的切割
                //默认输入输出重定向都是最后一个参数,输入时第一个管道,输出是最后一个管道
                if (cmdv[0]->argv[cmdv[0]->argc-1]!=NULL)
                {
                    char q[LEN];
                    strcpy(q,cmdv[0]->argv[cmdv[0]->argc-1]);
                    cat_in(q);//输入重定向
                }
                if (cmdv[num-1]->argv[cmdv[num-1]->argc-1]!=NULL)
                {
                    char q[LEN];
                    strcpy(q,cmdv[num-1]->argv[cmdv[num-1]->argc-1]);
                    cat_out(q);//输出重定向
                }
                do_pipe(0);//执行管道
                exit(0);
            }
            waitpid(pid,NULL,0);
        }
    }
    return 0;
}
时间: 2024-10-10 10:36:53

Linux 用C语言实现简单的shell(2)的相关文章

Linux 用C语言实现简单的shell

发一波福利,操作系统的实验内容,大家可以借鉴一下,不过我的代码可能也存在一定的问题. 因为在一开始老师是一节一节课教的,当时并不知道后面还会用输入输出重定向,管道等一系列问题,我的兴趣也不在这个方面也没有预习,所以一来代码写的比较丑,二来没有对于代码进行一个合理的规划,写的也比较乱. 代码暂时实现到输入输出重定向,之后可能会加上管道处理等方面的程序. 如果让我重新写这段代码应该会规划的更好一点吧 /*author:Samsons date:2015.4.10*/ #include <stdio.

Linux下C语言多线程,网络通信简单聊天程序

原文:Linux下C语言多线程,网络通信简单聊天程序 功能描述:程序应用多线程技术,可是实现1对N进行网络通信聊天.但至今没想出合适的退出机制,除了用Ctr+C.出于演示目的,这里采用UNIX域协议(文件系统套接字),程序分为客户端和服务端.应用select函数来实现异步的读写操作. 先说一下服务端:首先先创建套接字,然后绑定,接下进入一个无限循环,用accept函数,接受“连接”请求,然后调用创建线程函数,创造新的线程,进入下一个循环.这样每当有一个新的“连接”被接受都会创建一个新的线程,实现

shell 脚本实战笔记(11)--Mysql在linux下的安装和简单运维

前言: linux中安装mysql以及配置的管理, 基础的运维和管理还是需要会一些的. 这边作下笔记, 以求天天向上(^_^). 安装流程:*). 安装mysql-server1). 借助yum检索相关的mysql rpm包yum search mysqlmysql-server.x86_64 正是我们想要的 2). 安装mysql-serveryum install mysql-server.x86_64 -y默认mysql-client也安装好 3). 启动mysql服务/etc/init.

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

不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步:创建一个包含命令和控制结构的文件 第二步:修改这个文件的权限使它可以执行. 使用chmod u+x 第三步:执行shell sh /test/example.sh Shell变量 变量:是shell传递数据的一种方法,用来代表每个取值的符号名 shell有两类变量:临时变量和永久变量 临时变量是sh

UNIX/Linux下C语言的学习路线

一.工具篇 “公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具. 1.操作系统    在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux系统有FreeBSD.RedHat Linux.SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等. 如果您一直使用Window

linux 下C语言学习路线

转载:http://blog.csdn.net/xdw1985829/article/details/6817403 UNIX/Linux下C语言的学习路线. 一.工具篇 “公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具. 1.操作系统     在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux

一个简单的shell

最近按照mit的Operating System Engineering课程(6.828/Fall 2014)学习从零编写一个简单的操作系统. 第一节课的作业1就是写一个简单的shell,能够运行command,并且支持重定向(‘>’, ‘<’)和管道(‘|’),但不支持脚本编程. 课程给的源码已经实现了参数的解析 1 struct cmd * parsecmd(char *s); 该函数根据每行的命令中是否含有’>’/’<’和’|’返回不同的cmd结构: 1 struct cmd

二、Java语言的简单认识及Hello World示例

1. Java语言的简单认识 (1) Java有三个版本: a. JAVA SE (以前称J2SE):Standard Environment 标准版本: b. JAVA EE (以前称J2EE):Enterprise Environment 企业版: c. JAVA ME (以前称J2ME):Eicro Environment 微型版; (2) Java的安装目录 在前一讲中,提到安装目录中有两个文件夹,分别是jdk1.7.0_45和jre7.在"jdk1.7.0_45"文件夹的bi

Linux运维 第二阶段 (九)shell编程

Linux运维 第二阶段 (九)shell编程 一.1.基础正则表达式: *         前一个字符匹配0次或任意多次 .         匹配除了换行符外任意一个字符 ^         匹配行首,例:^Hello,匹配以Hello开头的行 $         匹配行尾,例:Hello$匹配以Hello结尾的行 []        中括号中指定的一个字符,例:[0-9].[a-z] [^]       匹配中括号字符以外的任意一个字符,例:[^0-9].[^a-z] \         转