Вызов потока канала popen() с помощью командной строки оболочки цикла

Я тестирую этот пример программирования с использованием каналов, и мне кажется довольно просто.

Но мне было интересно, что произойдет, если первый аргумент первого вызова popen() (строка, содержащая команду оболочки) содержит цикл while do.

Например, если я выполняю эту команду оболочки в течение 3 секунд, я получаю следующий вывод:

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

поэтому grep работает на каждой итерации.

Однако, если я сделаю это через пример языка C, изменив popen() примера на:

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

Я не получаю результата при выполнении скомпилированной программы C.

Кто-нибудь может пролить свет на это?


person nephewtom    schedule 02.10.2014    source источник
comment
Вы действительно читали из этого потока? Что вы сделали с выводом, который вы прочитали, и что вы ожидали увидеть? Трудно сказать, что может происходить без полной автономной программы.   -  person Useless    schedule 02.10.2014


Ответы (3)


Изменить: как заметил Дж. Ф. Себастьян, по умолчанию grep использует большие буферы, когда вывод не направляется на терминал. Вам нужно использовать опцию --line-buffered для немедленного вывода (после каждой строки)

Что ж, я попробовал, и он отлично работает (благодаря исправлению J.F. Sebastian). Вот полный код на коробке FreeBSD 9:

#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;

}

И (поскольку я не удалял \n в конце buffer) вывод:

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
>
person Serge Ballesta    schedule 02.10.2014
comment
@ J.F.Sebastian Я знаю, что это не та же команда, но она работает так же ... и мне лень запускать ее снова. Не стесняйтесь редактировать мой ответ с точной командой и соответствующим выводом или опубликовать свой собственный. - person Serge Ballesta; 02.10.2014
comment
Я уже опубликовал свой ответ. И я могу воспроизвести поведение, описанное в вопросе. Добавление grep имеет значение на моей машине (Ubuntu). - person jfs; 02.10.2014
comment
@ J.F.Sebastian: упс, ты прав! Я думаю, мне нужно отредактировать это :-( Большое спасибо, что заметили... - person Serge Ballesta; 02.10.2014

Это проблема блочной буферизации. Когда стандартный вывод grep не является терминалом (tty), например, когда это канал (созданный popen()), как в вашем случае; он использует буферизацию блоков вместо буферизации строк. Вы ничего не увидите, пока буфер stdout grep не переполнится. Добавьте параметр --line-buffered к grep, и вы сразу увидите результат (каждую секунду).

person jfs    schedule 02.10.2014
comment
У ОП была проблема просто с запуском FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "r");, у него не было проблем с grep (видите здесь что-то, связанное с grep?!), он просто пытался впервые поэкспериментировать с popen и сразу же столкнулся с проблемой не получить результат. Однако вы пропустили это и -1 за это! - person rakib_; 02.10.2014
comment
@rakib: OP говорит: Я не получаю результата вывода при выполнении скомпилированной программы C. но если вы запустите команду без grep, тогда проблемы с блочной буферизацией не возникнет (в по крайней мере на моей машине) и OP должен увидеть результат. С другой стороны, если я использую grep, я не получаю результата (так же, как OP). Вот почему наличие grep имеет большое значение. Я предполагаю, что OP неправильно скопировал свой код, т. Е. В его фактическом коде есть grep. - person jfs; 02.10.2014
comment
ОП не пытался с grep внутри popen(). Почему ты этого не понимаешь? Вы неправильно прочитали вопрос и расплывчато добавили объяснение --line-buffered. Пожалуйста, перечитайте вопрос еще раз и попытайтесь решить проблему, с которой сталкивается OP, не добавляйте свои поверхностные мысли. - person rakib_; 02.10.2014
comment
Зачем мне перечитывать последнее предложение? Ваш комментарий или то, что вы думаете поверхностно, для меня не имеет значения, это вопрос, о котором мы говорим, и он должен быть таким. В моем ответе вы найдете комментарий ОП о его замешательстве (что указывает на то, что он пытается изучить концепцию) о концепции, несмотря на то, что вы пытаетесь внедрить свою собственную мысль! - person rakib_; 02.10.2014

Все, что вам нужно сделать, это write вывести на стандартный ввод-вывод, поэтому измените popen() параметры на следующие:

          FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "w");
person rakib_    schedule 02.10.2014
comment
Я думаю, что OP пытается читать вывод этой команды оболочки, а не записывать ее ввод. - person Useless; 02.10.2014
comment
@Useless Я думаю, что OP говорит, что я не получаю результата при выполнении скомпилированной программы C. Речь о выводе, или я пропустил? - person rakib_; 02.10.2014
comment
Хорошо, это заставляет это работать... Но, боюсь, я не понимаю, почему... Думаю, мне нужно еще немного поучиться 8-) - person nephewtom; 02.10.2014
comment
Это будет работать, если вы никогда не читали вывод программы в своей версии, потому что теперь она разделяет стандартный вывод вашего родительского процесса. Если вы хотите прочитать эти строки в своем родительском процессе, вам нужно открыть окно для чтения (как вы это сделали), а затем действительно прочитать. - person Useless; 02.10.2014
comment
@ J.F.Sebastian Спасибо за ваше понимание, я думаю, я знаю, что такое чтение и письмо. Но правильно ли вы выбрали вопросы? - person rakib_; 02.10.2014
comment
@ Бесполезно Да, ты прав. Но совершенно очевидно, что у ОП проблемы с запуском его простой команды, и он понятия не имеет. И этот ответ поможет ему получить результат так, как он хочет, он не упомянул, каким именно способом он хочет (зачем ему идти на какой-то сложный способ его получения, когда у него проблемы с получением результата?). - person rakib_; 02.10.2014
comment
С вашим решением OP не программирует каналы в каком-либо значимом смысле - это просто разветвление и выполнение подпроцесса и позволяет ему наследовать стандартный вывод. - person Useless; 02.10.2014
comment
@Useless Спроси ОП, а не меня. Я вижу, у вас серьезные проблемы с пониманием того, что ОП только учится, и он в замешательстве, взгляните на его комментарий после моего ответа. Даже это тебе непонятно, тогда просто до свидания. - person rakib_; 03.10.2014