c - 几乎完成了 linux shell pipe

标签 c linux shell pipe dup2

您好,我正在尝试在 Linux 上构建一个 shell,但我被流水线部分卡住了。首先,我从用户那里获取输入,例如“ls | sort”,然后当我尝试运行该程序时,它看起来像命令 ls 和排序不起作用 看起来我已经做对了所有事情,但似乎仍然无法正常工作。你能帮忙吗提前致谢

include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <fcntl.h>
#include <sys/stat.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int setup();

int main(int argc, const char * argv[])
{

    while(1)

    {
        printf("333sh: ");
        if(setup())
            break;
    }

    return 0;
}
int setup(){




    char  input [128];
    char *arg[32];
    int i = 1;
    while(fgets(input,128,stdin)!=NULL)
    {
        arg[0] = strtok(input," \n");
        while((arg[i]=strtok(NULL," \n")) != NULL){
            i++;
            }



           if (arg[1]!=NULL && strcmp(arg[1],"|")==0 && arg[2]!=NULL ){
            pid_t pid;

            int fd[3];

        pipe(fd);

    pid=fork();
        if(pid<0){
            printf("fork");
        }
        else if(pid==0){
            pid_t cpid;

            cpid=fork();
                if(cpid==0){

                    dup2(fd[2], 1); // Replace stdin with the read end of the pipe
                    close(fd[0]); // Don't need another copy of the pipe read end hanging about
                    close(fd[2]);
                    execvp(arg[0],arg);
        }
                else if(pid>0){

                    dup2(fd[0], 0); // Replace stdout with the write end of the pipe
                    close(fd[0]); //close read from pipe, in parent
                    close(fd[2]); // Don't need another copy of the pipe write end hanging about
                    execvp(arg[2], arg);
        }
    }
        else if(pid>0){
            waitpid(pid, NULL,0);
  }

        }


            }





    }

最佳答案

您最大的问题是您的命令的参数列表格式错误(在您解决了索引 2 与索引 1 问题后,管道文件描述符由 Ben Jackson 在他的 answer 中诊断)。

我添加了一个函数:

static void dump_args(int pid, char **argv)
{
    int i = 0;
    fprintf(stderr, "args for %d:\n", pid);
    while (*argv != 0)
        fprintf(stderr, "%d: [%s]\n", i++, *argv++);
}

并在调用 execvp() 之前调用它,我得到的输出是:

$ ./ns
333sh: ls | sort
args for 29780:
0: [ls]
1: [|]
2: [sort]
ls: sort: No such file or directory
ls: |: No such file or directory
^C
$

control-C 是我打断了程序。每个命令的参数必须是“命令名称”(通常是可执行文件的名称),后跟其余参数和一个空指针。

您的标记化代码没有提供两个正确的命令。

您还对正在查看的 PID 有疑问:

                cpid = fork();
                if (cpid == 0)
                {
                    dup2(fd[1], 1);
                    close(fd[0]);
                    close(fd[1]);
                    dump_args(getpid(), arg);
                    execvp(arg[0], arg);
                    fprintf(stderr, "Failed to exec %s\n", arg[0]);
                    exit(1);
                }
                else if (pid > 0)  // should be cpid!
                {
                    dup2(fd[0], 0);
                    close(fd[0]);
                    close(fd[1]);
                    dump_args(pid, arg);
                    execvp(arg[1], arg);
                    fprintf(stderr, "Failed to exec %s\n", arg[1]);
                    exit(1);
                }

还需要在等待前关闭父进程中的管道文件描述符。

此代码为简单的 x | 编译和“工作” y 命令序列,例如 ls |排序ls |排序 -r。但是,这远非通用解决方案。在获得通用解决方案之前,您需要大量修复参数解析代码。

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

int setup(void);

int main(void)
{
    while (1)
    {
        printf("333sh: ");
        if (setup())
            break;
    }
    return 0;
}

static void dump_args(int pid, char **argv)
{
    int i = 0;
    fprintf(stderr, "args for %d:\n", pid);
    while (*argv != 0)
        fprintf(stderr, "%d: [%s]\n", i++, *argv++);
}

int setup(void)
{
    char input[128];
    char *arg[32];
    int i = 1;
    while (fgets(input, sizeof(input), stdin) != NULL)
    {
        arg[0] = strtok(input, " \n");
        while ((arg[i] = strtok(NULL, " \n")) != NULL)
        {
            i++;
        }
        if (arg[1] != NULL && strcmp(arg[1], "|") == 0 && arg[2] != NULL)
        {
            pid_t pid;
            int fd[2];
            arg[1] = NULL;

            pipe(fd);

            pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "fork failed\n");
                return 1;
            }
            else if (pid == 0)
            {
                pid_t cpid = fork();
                if (cpid < 0)
                {
                    fprintf(stderr, "fork failed\n");
                    return 1;
                }
                else if (cpid == 0)
                {
                    printf("Writer: [%s]\n", arg[0]);
                    dup2(fd[1], 1);
                    close(fd[0]);
                    close(fd[1]);
                    dump_args(getpid(), arg);
                    execvp(arg[0], arg);
                    fprintf(stderr, "Failed to exec %s\n", arg[0]);
                    exit(1);
                }
                else
                {
                    printf("Reader: [%s]\n", arg[2]);
                    assert(cpid > 0);
                    dup2(fd[0], 0);
                    close(fd[0]);
                    close(fd[1]);
                    dump_args(getpid(), &arg[2]);
                    execvp(arg[2], &arg[2]);
                    fprintf(stderr, "Failed to exec %s\n", arg[2]);
                    exit(1);
                }
            }
            else
            {
                close(fd[0]);
                close(fd[1]);
                assert(pid > 0);
                while (waitpid(pid, NULL, 0) != -1)
                    ;
            }
        }
    }
    return 1;
}

关于c - 几乎完成了 linux shell pipe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20435092/

相关文章:

c - 如何在mingw中检测命令行参数的字符编码

linux - Node Exporter 绑定(bind)地址已经运行

linux - 从套接字读取失败 : Connection reset by peer

windows - 如何在 Unix(或 Windows)中使用(最好是未命名的)管道将一个进程的标准输出发送到多个进程?

c - gdb共享库没有调试信息

c - 如何更改 Xcode 中的编译器

linux - 处理将参数传递给嵌套脚本调用并创建有效的菜单驱动 cli 的最佳方法

c - 为什么扩展 grep 不起作用?

android - shell-查找文件中的su命令的结果android

c++ - Linux 中的静态链接可移植吗?