【问题标题】:How to pipe in C [duplicate]如何在C中管道[重复]
【发布时间】:2016-08-22 06:03:50
【问题描述】:

所以,我想在 C 中执行以下命令行:

 ps -eo user,pid,ppid 2> log.txt | grep user 2>>log.txt | sort -nk2 > out.txt

但我不确定,代码怎么会是…… 我很困惑如何将命令的输出写入文件,正确和错误输出......

另外,我不知道应该如何构建管道以及当 pid == -1 或 pid > 0 时该怎么做...

我的代码如下:

int main(){

    int fd0[2], fd1[2], pid0, pid1;

    pipe(fd0);
    pid0 = fork();
    if (pid == 0){
        close(1);
        dup(fd0[0]);
        fd_file= open(“./out.txt”, O_WRONLY | O_CREAT | O_TRUNC, 00600);
        execl("sort","-nk2",">fd_file");
        pipe(fd1);
        pid1 = fork();
        if (pid1 == 0){ 
            close(1);
            dup(fd1[0]);
            ...?
        }

    }
    else if (pid == -1){
        perror("ERROR AT SORT!\n");
        exit(1);
    }

    return 0;
}

【问题讨论】:

  • 为了处理错误,最好的办法可能是退出(在main()exit() 中返回)。
  • 不要在传递给perror的字符串末尾添加换行符。 perror 将打印您的字符串,后跟 :,如果冒号从新行开始,这看起来很奇怪。
  • execl 之后的下一行只有在execl 失败时才会执行。
  • execl 中的">fd_file" 将作为参数传递给sort,它不会进行重定向 - 这是由 shell 完成的,并且您没有运行 shell。

标签: c bash command pipe ps


【解决方案1】:

虽然链接两个命令看起来很简单,但尝试链接更多命令却有点棘手。我给出了一个程序,它可以很容易地泛化为链接任意数量的命令。我更喜欢将第一个进程作为所有进程的父进程。

请阅读 cmets 以获得更详细的解释。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>


// Better to use define for constants
#define SUB_PROCESSES_NUMBER 2
#define FILE_OUT "out.txt"
#define FILE_LOGS "log.txt"

char *command0[] = {"ps", "-eo" "user,pid,ppid", NULL};
char *command1[] = {"grep", "^user", NULL}; // "^user" matches lines starting with "user"
char *command2[] = {"sort", "-nk2", NULL};
char **commands[SUB_PROCESSES_NUMBER + 1] = {command0, command1, command2};

int main(){
    pid_t pid[SUB_PROCESSES_NUMBER]; // good practice: fork() result is pid_t, not int
    int fd[SUB_PROCESSES_NUMBER][2];

    // I recommend opening files now, so if you can't you won't create unecessary processes
    int fd_file_out = open(FILE_OUT, O_WRONLY | O_CREAT | O_TRUNC, 00600);
    if (fd_file_out < 0)
    {
        perror("open(" FILE_OUT ")");
        return 2;
    }

    int fd_file_logs = open(FILE_LOGS, O_WRONLY | O_CREAT | O_TRUNC, 00600);
    if (fd_file_logs < 0)
    {
        perror("open(" FILE_LOGS ")");
        close(fd_file_out); // Not necessary, but I like to do it explicitly
        return 2;
    }

    for (int i = 0; i < SUB_PROCESSES_NUMBER; i++) // If you decide to add more steps, this loop will be handy
    {
        if (pipe(fd[i]) < 0)
        {
            perror("pipe");
            close(fd_file_out);
            close(fd_file_logs);
            if (i > 0)
            {
                close(fd[i - 1][0]);
            }
            return 2;
        }

        pid[i] = fork();
        if (pid[i] < 0)
        {
            perror("fork()");
            close(fd_file_out);
            close(fd_file_logs);
            if (i > 0)
            {
                close(fd[i - 1][0]);
            }
            close(fd[i][0]);
            close(fd[i][1]);
            return 2;
        }

        if (pid[i] == 0)
        {
            close(fd[i][0]); // First thing to do: close pipes and files you don't need any more
            close(fd_file_out);

            close(1);
            dup(fd[i][1]);
            close(fd[i][1]); // duplicated pipes are not useful any more

            close(2); // Also need to redirect stderr
            dup(fd_file_logs);
            close(fd_file_logs);

            if (i > 0)
            {
                close(0); // Also need to redirect stdin if this is not first process
                dup(fd[i - 1][0]);
                close(fd[i - 1][0]);
            }

            execvp(commands[i][0], commands[i]); // In a loop, we need a execv()/execvp()/execvpe() call
            return 2; // Should not be reached;
        }

        // sub process either did execvp() or return, he won't reach this point
        close(fd[i][1]);
        if (i > 0)
        {
            close(fd[i - 1][0]);
        }
    }

    close(fd_file_logs);

    close(0);
    dup(fd[SUB_PROCESSES_NUMBER - 1][0]);
    close(fd[SUB_PROCESSES_NUMBER - 1][0]);

    close(1);
    dup(fd_file_out);
    close(fd_file_out);

    execvp(commands[SUB_PROCESSES_NUMBER][0], commands[SUB_PROCESSES_NUMBER]);
    perror("execvp");
    return 2;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多