C / Linux - 重定向stdin和stout时遇到问题

时间:2017-02-01 05:29:42

标签: c linux io-redirection

我有以下程序:

int main(int argc, char **argv)
{
    char    *program;
    char     stringa[1000] = "";
    int num = 0;
    char snum[10];
    int pipefd[2];
    pipe(pipefd);
    program = argv[1];   

    sprintf(stringa, "./%s", program);

    pid_t pid = fork();
    if (pid < 0 ) {
        perror("fork failed."); 
        exit(1);
    }
    else if (pid == 0) { 
        char* args[] = {stringa, NULL};
        execv(args[0], args);
    }
    else {   
       char procmon_str[] = "./procmon";
       num = pid;
       sprintf(snum, "%d",num);

       pid_t pid2 = fork();
       if (pid2 == 0) { //launch procmon
           char* args2[] = {procmon_str, snum, NULL};

           close(pipefd[0]); //close reading end in the child
           dup2(pipefd[1], 1); //send stdout to the pipe
           dup2(pipefd[1], 2); //send stderr to the pipe
           close(pipefd[1]); //this descriptor is no longer needed

           execv(args2[0], args2);
       }
       else { 
           close(pipefd[1]);
           dup2(pipefd[0], STDIN_FILENO);
           close(pipefd[0]);
           char* args3[] = {"./filter", NULL};
           execv(args3[0], args3);    
       }
    }

   return 0;
}

我是这样推出的:

./myProgram process

然后,发生以下情况:

  • myProgram启动process并确定其PID
  • 然后使用相同的procmon
  • 启动PID程序
  • 它将启动另一个运行程序filter
  • 的进程

procmon的输出应发送到filter的输入,意思是 - filter将从其标准输入中读取procmon写入其标准输出的内容。

出于某种原因,我没有得到预期的结果。

procmon的工作是获取给定进程的PID,访问相应的/proc/PID/stat文件并打印进程状态。 filter需要接受它,并且只打印状态从一个变为另一个的行。目前,我没有从filter得到任何东西。

process进入循环(10次迭代),休眠3秒,然后启动另一个循环,使变量增加400,000次。

我做得对吗?

1 个答案:

答案 0 :(得分:3)

&#34;没有得到预期的结果&#34;不能很好地描述你所面临的问题。

总的来说,代码还不错。我做了一些重大更改和一些无关紧要的更改(移动变量声明,初始化变量而不是分配它们,格式化)。重大变化包括:

  • 检查是否使用参数调用程序。
  • 在创建第一个子项之前不创建管道。
  • 报告错误并在execv()失败时退出。
  • 不将procmon进程的标准错误重定向到管道。

管道创建可能很重要。如最初编写的那样,process管道的两端都打开了,因此filterprocess继续时不会在管道上获得EOF。由于process不太可能使用管道(它没有正式知道哪些文件描述符对它们开放),所以确实没有意义,可能会对管道保持打开造成一定的伤害。

不将标准错误重定向到管道允许我在我使用的测试脚本中看到没有shebang的错误消息。

我使用了stderr.hstderr.c中的一组函数,这些函数可以在https://github.com/jleffler/soq/tree/master/src/libsoq的GitHub上找到。它们简化了错误报告,因此我的大多数程序都使用它们。

这导致了以下代码,它与您所拥有的代码类似:

#include "stderr.h"
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    if (argc != 2)
        err_usage("program");

    pid_t pid = fork();
    if (pid < 0)
        err_syserr("failed to fork");
    else if (pid == 0)
    {
        char stringa[1000] = "";
        char    *program = argv[1];
        sprintf(stringa, "./%s", program);
        char *args[] = {stringa, NULL};
        execv(args[0], args);
        err_syserr("failed to execute '%s': ", args[0]);
    }
    else
    {
        int pipefd[2];
        pipe(pipefd);

        pid_t pid2 = fork();
        if (pid2 < 0)
            err_syserr("failed to fork");
        else if (pid2 == 0)    // launch procmon
        {
            int num = pid;
            char snum[10];
            sprintf(snum, "%d", num);
            char procmon_str[] = "./procmon";
            char *args2[] = {procmon_str, snum, NULL};

            close(pipefd[0]); // close reading end in the child
            dup2(pipefd[1], 1); // send stdout to the pipe
            //dup2(pipefd[1], 2); // send stderr to the pipe
            close(pipefd[1]); // this descriptor is no longer needed
            execv(args2[0], args2);
            err_syserr("failed to execute '%s': ", args2[0]);
        }
        else
        {
            close(pipefd[1]);
            dup2(pipefd[0], STDIN_FILENO);
            close(pipefd[0]);
            char *args3[] = {"./filter", NULL};
            execv(args3[0], args3);
            err_syserr("failed to execute '%s': ", args3[0]);
        }
    }
    /*NOTREACHED*/
    return 0;
}

然后我遇到了测试这个问题。我创建了三个shell脚本 - processprocmonfilter。似乎process做什么并不重要,只要它需要一些时间来做。 procmon可能是为了监控流程的状态;它不能成为标准程序,因为您在当前目录中运行它。同样,filter可能意味着修改它从输入中读取的内容。所以,我发明了脚本来完成这些工作:

<强>过程

#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $$" -r 0.2 -s 0.5 -t

<强>将procmon

#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $1" -r 0.3 -t

过滤

#!/bin/sh
echo "$0 at work"
exec grep -e '^[0-9]*9[0-9]*:' -- -

dribbler程序是一个家庭酿造,慢慢地写信息,和timeout程序(也是家庭酿造,版本回到1989年,而不是同名的GNU程序)在指定时间后停止其过程。 -r的{​​{1}}和-s选项实现了高斯时间分布(dribbler平均睡眠时间,默认为1秒,-s标准差为随机性)。 -r脚本宣布它正忙,然后在输出的第一个字段中查找9。

有了这个基础设施,我的输出就像:

filter

$ pp37 process ./filter at work 0: ./process: PID 48812 1: ./process: PID 48812 2: ./process: PID 48812 … 9: ./process: PID 48812 10: ./process: PID 48812 … 20: ./process: PID 48812 21: ./process: PID 48812 9: ./procmon: PID 48812 22: ./process: PID 48812 23: ./process: PID 48812 … 92: ./process: PID 48812 93: ./process: PID 48812 49: ./procmon: PID 48812 94: ./process: PID 48812 95: ./process: PID 48812 96: ./process: PID 48812 97: ./process: PID 48812 98: ./process: PID 48812 99: ./process: PID 48812 100: ./process: PID 48812 101: ./process: PID 48812 102: ./process: PID 48812 … 116: ./process: PID 48812 117: ./process: PID 48812 59: ./procmon: PID 48812 118: ./process: PID 48812 119: ./process: PID 48812 … 140: ./process: PID 48812 69: ./procmon: PID 48812 141: ./process: PID 48812 … 161: ./process: PID 48812 162: ./process: PID 48812 79: ./procmon: PID 48812 163: ./process: PID 48812 … 179: ./process: PID 48812 180: ./process: PID 48812 89: ./procmon: PID 48812 181: ./process: PID 48812 182: ./process: PID 48812 90: ./procmon: PID 48812 183: ./process: PID 48812 91: ./procmon: PID 48812 184: ./process: PID 48812 185: ./process: PID 48812 186: ./process: PID 48812 92: ./procmon: PID 48812 187: ./process: PID 48812 188: ./process: PID 48812 93: ./procmon: PID 48812 189: ./process: PID 48812 94: ./procmon: PID 48812 190: ./process: PID 48812 191: ./process: PID 48812 95: ./procmon: PID 48812 192: ./process: PID 48812 193: ./process: PID 48812 96: ./procmon: PID 48812 194: ./process: PID 48812 195: ./process: PID 48812 196: ./process: PID 48812 97: ./procmon: PID 48812 197: ./process: PID 48812 98: ./procmon: PID 48812 198: ./process: PID 48812 199: ./process: PID 48812 200: ./process: PID 48812 201: ./process: PID 48812 99: ./procmon: PID 48812 202: ./process: PID 48812 … 220: ./process: PID 48812 109: ./procmon: PID 48812 221: ./process: PID 48812 … 234: ./process: PID 48812 235: ./process: PID 48812 $ 的输出未被过滤,因此显示了该行的每一行,但过滤了process的输出,只显示了带有procmon的行。这似乎表现得很正确。