首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C/Linux -在重定向stdin和stout方面有问题

C/Linux -在重定向stdin和stout方面有问题
EN

Stack Overflow用户
提问于 2017-02-01 05:29:42
回答 1查看 426关注 0票数 1

我有以下节目:

代码语言:javascript
复制
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;
}

我是这样发起的:

代码语言:javascript
复制
./myProgram process

然后,发生以下情况:

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

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

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

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

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

我做得对吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-01 15:19:14

“不要得到想要的结果”并不能很好地描述你所面临的问题。

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

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

管道的创建可能很重要。正如最初所写的,process打开了管道的两端,因此在process继续时,filter不会在管道上获得EOF。由于process不太可能使用管道(它不知道哪些文件描述符是为它们打开的),所以保持管道打开是没有意义的,也可能有一些危害。

如果没有将标准错误重定向到管道,我就可以在使用的测试脚本中看到一个错误消息。

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

这将导致以下代码,这与您拥有的代码非常相似:

代码语言:javascript
复制
#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的目的可能是修改它从输入中读取的内容。所以,我发明了脚本来做那些工作:

过程

代码语言:javascript
复制
#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $$" -r 0.2 -s 0.5 -t

procmon

代码语言:javascript
复制
#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $1" -r 0.3 -t

滤波器

代码语言:javascript
复制
#!/bin/sh
echo "$0 at work"
exec grep -e '^[0-9]*9[0-9]*:' -- -

dribbler程序是一个缓慢写入信息的家庭brew程序,而timeout程序(也是家庭brew程序,其版本可以追溯到1989年,而不是同名的GNU程序)在指定的时间后停止其进程。-r-s选项用于dribbler实现高斯时间分布(-s是平均睡眠时间,默认为1秒,-r为随机度的标准差)。filter脚本宣布它很忙,然后在输出的第一个字段中查找9s。

有了这些基础设施,我得到了如下输出:

代码语言:javascript
复制
$ 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的输出会被过滤,并且只显示带有9的行。这似乎是正确的行为。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41972528

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档