nephewtom
nephewtom

Reputation: 3121

Calling popen() pipe stream with a loop shell command line

I'm testing this example for programming with pipes and it seems pretty straightforward.

But I was wondering what happen if the first argument of first popen() call (the string containing a shell command) holds a 'while do' loop.

For example, if I execute this shell command for 3 seconds, I get this output:

tomas@ubuntu64:~$ while true; do ps -A; sleep 1; done | grep init
    1 ?        00:00:03 init
    1 ?        00:00:03 init
    1 ?        00:00:03 init

so the grep is working in each iteration.

However, if I do it through the C language example, changing the popen() of the example by:

FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "r");

I get no output result when executing the compiled C program.

Anyone can shed some light on this?

Upvotes: 3

Views: 1476

Answers (3)

Serge Ballesta
Serge Ballesta

Reputation: 148890

Edit: As noticed by J.F. Sebastian, by default grep uses large buffers when output is not directed to a terminal. You need to use option --line-buffered to get output immediately (after each line)

Well, I tried it and it works fine (thank to the fix of J.F. Sebastian). Here's full code on a FreeBSD 9 box :

#include <stdio.h>

int main() {

    char buffer[256];

    FILE *fd = popen("while true; do ps -A; sleep 1; done | grep --line-buffered init", "r");

        while(NULL != fgets(buffer, sizeof(buffer), fd)) {
            printf("GOT >%s<\n", buffer);
        }

    return 0;

}

And (as I did not remove the \n at end of buffer) the output is :

GOT >   1 ??  ILs    0:00:02 /sbin/init --
>
GOT >1334 v0  R+     0:00:00 grep --line-buffered init
>
GOT >   1 ??  ILs    0:00:02 /sbin/init --
>
GOT >1334 v0  R+     0:00:00 grep --line-buffered init
>

Upvotes: 2

jfs
jfs

Reputation: 414179

It is a block-buffering issue. When grep's stdout is not a terminal (tty) e.g., when it is a pipe (created by popen()) as in your case; it uses block buffering instead of line buffering. You won't see anything until grep's stdout buffer overflows. Add --line-buffered parameter to grep and you'll see the output immediately (each second).

Upvotes: 1

rakib_
rakib_

Reputation: 142625

All you need to do is to write the output to standard I/O, therefore change the popen() parameters to the following:

          FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "w");

Upvotes: -1

Related Questions