码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-04-29 00:33:31      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

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

 

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

标签:

原文地址:http://www.cnblogs.com/samsons/p/4464452.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!