LINUX.ORG.RU

Чтение выхлопа процесса без ожидания его завершения

 


0

3

Запускаю процесс через fork+execl. Хочу по мере его вывода читать его stdout.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

int main() {
  int filedes[2];
  if (pipe(filedes) == -1) {
    perror("pipe");
    exit(1);
  }

  pid_t pid = fork();
  if (pid == -1) {
    perror("fork");
    exit(1);
  } else if (pid == 0) {
    while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
    close(filedes[1]);
    close(filedes[0]);
    execl("/tmp/sub.exe", "/tmp/sub.exe", (char * ) 0);
    perror("execl");
    _exit(1);
  }
  close(filedes[1]);

  int flags;
  flags = fcntl(filedes[0], F_GETFL, 0);
  flags |= O_NONBLOCK;
  fcntl(filedes[0], F_SETFL, flags);

  flags = fcntl(filedes[1], F_GETFL, 0);
  flags |= O_NONBLOCK;
  fcntl(filedes[1], F_SETFL, flags);

  printf("ready\n");

  char buffer[4096];
  while (1) {
    ssize_t count = read(filedes[0], buffer, sizeof(buffer));
    if (count == -1) {
      if (errno == EINTR || errno == EWOULDBLOCK) {
        continue;
      } else {
        perror("read");
        exit(1);
      }
    } else if (count == 0) {
      break;
    } else {
      printf("%u: %d/%s\n", time(NULL), (int) count, buffer);
    }
  }
  close(filedes[0]);
  wait(0);
}

Sub:

#include <stdio.h>
#include <unistd.h>
# include <stdio.h>  
# include <string.h>  
# include <errno.h>  
#include <unistd.h>
#include <fcntl.h>

main() {
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
    sleep(1);
    printf("1111111111\n\n\n");
}

Не выходит каменный цветок. Ждет, зараза, пока sub не завершится, а потом выводит весь его выхлоп разом. Почему и как бороться?

★★★★★

stdout буферизуется построчно, если это терминальное устройство или блоками по X килобайт, если это файл. Бороться так:

  • если читать хочешь вывод своего процесса, то просто в самом начале сделай
    setlinebuf(stdout)
  • если хочешь читать вывод чего-то другого, основанного на libc, делаешь библиотечку, которая перехватывает вызов isatty и возвращает единичку для файлового дескриптора 1, но это чревато (например, ls/grep в режиме --color=auto будут писать escape-последовательности цветов)
kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

если хочешь читать вывод чего-то другого, основанного на libc, делаешь библиотечку, которая перехватывает вызов isatty и возвращает единичку для файлового дескриптора 1

Windows way?

Для этого в линуксе есть псевдотерминал.

Deleted
()
Ответ на: комментарий от next_time

к слову, где бы глянуть стандарт на это дело?

https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

Кусок о vt100 умеют все эмуляторы терминала — это то, что они эмулируют.

Остальное, типа сдвинуть окно на экране по координатам — зоопарк.

anonymous
()
Ответ на: комментарий от kawaii_neko

isatty

Удачи с декодированием escape sequences!

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.