C/Linux-重定向stdin和stout时遇到麻烦 [英] C/Linux - having trouble with redirecting stdin and stout

查看:101
本文介绍了C/Linux-重定向stdin和stout时遇到麻烦的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下程序:

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
  • 然后使用相同的PID
  • 启动procmon程序
  • 它将启动另一个运行程序filter
  • 的进程
  • myProgram launches process and determines its PID
  • It then launches the procmon program with that same PID
  • It will launch another process that runs the program filter

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

The output of procmon should be sent to the input of filter, meaning - filter will read from its standard input what procmon is writing to its standard output.

由于某种原因,我没有得到想要的结果.

For some reason, i don't get the desired results.

procmon的工作是获取给定进程的PID,访问相应的/proc/PID/stat文件并打印进程状态. filter需要采取这种措施,并且仅打印状态从一种更改为另一种的行.目前,我没有从filter那里得到任何东西.

procmons job is to take a given process's PID, access the corresponding /proc/PID/stat file and print the process state. filter needs to take that and only prints the line where the state changes from one to another. At the moment, i don't get anything from filter.

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

process goes into a loop (10 iterations) that sleeps for 3 seconds, and then starts another loop that increments a variable 400,000 times.

我做对了吗?

推荐答案

未获得期望的结果"不是对您所面临问题的很好描述.

"Don't get the desired results" is not a good description of the problem you are facing.

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

On the whole, the code is not bad. I've made some significant changes and a load of insignificant ones (moving variable declarations, initializing variables instead of assigning them, formatting). The significant changes include:

  • 检查是否已使用参数调用程序.
  • 在创建第一个孩子之后才创建管道.
  • 报告错误,如果execv()失败,则退出.
  • 不将procmon进程的标准错误重定向到管道.
  • Checking that the program is called with an argument.
  • Not creating the pipe until after the first child is created.
  • Reporting errors and exiting if the execv() fails.
  • Not redirecting standard error of the procmon process to the pipe.

管道的创建可能很重要.如最初所写,process的两端都打开,因此filter在继续执行process时不会在管道上产生EOF.由于process不太可能使用管道(它没有为它们打开哪些文件描述符的正式知识),所以确实没有意义,而且保持管道打开也可能有一定危害.

The pipe creation might be important. As originally written, the process had both ends of the pipe open, so filter would not get EOF on the pipe while process continued. Since process is unlikely to use the pipe (it has no formal knowledge of which file descriptors are open for them), there really is no point and could be some harm in keeping the pipe open.

未将标准错误重定向到管道,这使我看到了错误消息,原因是我使用的测试脚本中没有弹出按钮.

Not redirecting standard error to the pipe allowed me to see an error message from not having a shebang in the test scripts I used.

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

I used a set of functions from stderr.h and stderr.c, which are available on GitHub at https://github.com/jleffler/soq/tree/master/src/libsoq. They simplify error reporting, so most of my programs use them.

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

This leads to the following code, which is recognizably similar to what you have:

#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可能意味着修改它从输入中读取的内容.因此,我发明了脚本来完成这些工作:

I was then faced with the problem of testing this. I created three shell scripts — process, procmon and filter. It seems that it is not critical what process does as long as it takes some time doing it. The procmon is probably meant to monitor a process's status; it can't be a standard program because you run it in the current directory. Similarly, filter is presumably meant to modify what it reads from its input. So, I invented scripts to do those jobs:

过程

#!/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程序(也是Home-brew,其版本可以追溯到1989年,而不是同名的GNU程序)在指定的时间. dribbler-r-s选项实现高斯时间分布(-s平均睡眠时间,默认为一秒,-r随机性的标准偏差). filter脚本宣布它正忙,然后在输出的第一个字段中查找9s.

The dribbler program is a home-brew that writes information slowly, and the timeout program (also home-brew, with versions back to 1989, rather than the GNU program of the same name) stops its process after a designated time. The -r and -s options to dribbler implement a Gaussian time distribution (-s the mean sleep time, defaulting to one second, -r the standard deviation of the randomness). The filter script announces that it is busy and then looks for 9s in the first field of the output.

有了该基础架构,我得到的输出如下:

With that infrastructure, I got output like:

$ 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的行.这似乎行为正确.

The output of process is not filtered so every line of that is shown, but the output of procmon is filtered and only lines with a 9 are shown. This seems to be behaving correctly.

这篇关于C/Linux-重定向stdin和stout时遇到麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆