Chinaunix首页 | 论坛 | 博客
  • 博客访问: 147155
  • 博文数量: 27
  • 博客积分: 2011
  • 博客等级: 大尉
  • 技术积分: 332
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-02 16:13
文章分类

全部博文(27)

文章存档

2009年(18)

2008年(9)

我的朋友

分类: C/C++

2008-12-08 11:44:36

    运行时, 提示键入两个命令中间用 | 隔开
    执行 | 隔开的两个命令, 第一个的输出重定向到第二个的输入
    如:
    shell_pipe
    >ls -l | more

实现管道的步骤
    父进程解析得到两个命令
    fork一个子进程,子进程创建pipe,作为输入端,并用dup2复制给stdin
    子进程再fork一个子进程,孙进程使用pipe的输出端,并用dup2复制给stdout

/*
 * 简单的shell管道模拟实现
 */


#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define MAX_OPT_NUM 32 // 最多选项个数

#define MAX_OPT_LEN 128 // 最大选项长度


void separatecmd(const char *cmd, char **argv1, char **argv2);

int main()
{
    // -----------------------

    // 得到两个命令

    // -----------------------

    char cmd[128];
    char **argv1 = malloc(sizeof(char*)*MAX_OPT_NUM);
    char **argv2 = malloc(sizeof(char*)*MAX_OPT_NUM);
    memset(argv1, 0, sizeof(argv1));
    memset(argv2, 0, sizeof(argv2));
    
    printf("input two command seperated by |, stdout of cmd1 will be redirected to stdin of cmd2\n");
    printf(">");
    fgets(cmd, 128, stdin);
    cmd[strlen(cmd)-1] = 0; // 最后一个换行符要去掉, 否则execvp报错


    separatecmd(cmd, argv1, argv2);

    int pid;
    if((pid = fork()) == 0)
    {
        int fd[2];
        pipe(fd);
        if(fork() == 0) // 孙进程 执行第二个命令

        {
            close(fd[1]);
            dup2(fd[0], 0);
            execvp(argv2[0], argv2);
        }

        close(fd[0]);
        dup2(fd[1], 1);
        execvp(argv1[0], argv1); // 子进程 执行第一个命令

    }
    
    wait(NULL);

    return 0;
}

void separatecmd(const char *cmd, char **argv1, char **argv2)
{
    int cmd_opt_cnt1 = 0;
    int cmd_opt_cnt2 = 0;
    
    char token[MAX_OPT_LEN];
    memset(token, 0, sizeof(token));
    int token_cnt = 0;
    
    int flag = 0; // 现在是命令1还是命令2

    
    for(int i=0; i<strlen(cmd); i++)
    {
        if(cmd[i] == '|' || cmd[i] == ' ')
        {
            if(strlen(token) > 0)
            {
                if(flag == 0) // command 1

                {
                    argv1[cmd_opt_cnt1] = malloc(strlen(token) + 1);
                    strcpy(argv1[cmd_opt_cnt1], token);
                    cmd_opt_cnt1 ++;
                }
                else // command 2

                {
                    argv2[cmd_opt_cnt2] = malloc(strlen(token) + 1);
                    strcpy(argv2[cmd_opt_cnt2], token);
                    cmd_opt_cnt2 ++;
                }
            }
            if(cmd[i] == '|')
            {
                flag = 1;
            }
            memset(token, 0, sizeof(token));
            token_cnt = 0;
        }
        else
        {
            token[token_cnt] = cmd[i];
            token_cnt ++;
        }
    }
    if(token_cnt > 0)
    {
        argv2[cmd_opt_cnt2] = malloc(strlen(token) + 1);
        strcpy(argv2[cmd_opt_cnt2], token);
        cmd_opt_cnt2 ++;
    }
}

阅读(1100) | 评论(2) | 转发(0) |
0

上一篇:vmware fedora9

下一篇:安装启动lighttpd

给主人留下些什么吧!~~

zhongyj2009-03-31 10:21:35

在solaris下用cc编译通过了,有警告 加上你说的两个没有了 你编译不过可能是用的gcc吧 运行通过了,代码自己敲的

chinaunix网友2009-03-26 12:50:04

少了两个头文件 另:这个代码是您写的吗?运行通过了?