Остановить перехват out и err

142
01 апреля 2021, 22:30

Начинаю перехват потоков out и err в файл, но как остановить перехват после выполнения определенной команды?

int file_desc = open(path_out.c_str(), O_WRONLY | O_APPEND);
dup2(file_desc,2);
dup2(file_desc,1);
Answer 1

Вот, набросал примерчик, когда вывод stdout/stderr сначала переключается на вывод в лог, а потом восстанавливается на ранее связанные с этими дескрипторами ресурсы.

Основная идея состоит в том, что перед переключением дескрипторов stdout/stderr с помощью dup2() их необходимо сохранить, сделав копию системным вызовом dup().

После окончания "перехвата" восстанавливаем связь дескрипторов 1/2 (stdout/stderr) с первоначальными ресурсами (используем опять же dup2(), чтобы сразу закрыть их ссылки на лог), а затем закрываем ранее созданные копии дескрипторов (поскольку ресурс файловых дескрипторов процесса ограничен (хотя, в данном примере это и не важно)).

Надеюсь, комментарии в тексте программы достаточно проясняют суть процесса.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int
main (int ac, char *av[])
{
  FILE *log = fopen(av[1], "w");
  puts("Go...");
  fputs("1\n", log); fflush(log);  // первый вывод напрямую в лог 
  perror("Start");   // это пока еще выводится в консоль
  int save1 = dup(1), save2 = dup(2);  //  важно, сохраним исходные stdout-stderr
  int ofd = dup2(fileno(log), 1);   // теперь вывод stdout пойдет в log
  int efd = dup2(fileno(log), 2);   // теперь вывод stderr пойдет в log
  printf("dup2: %d  out: %d\n", ofd, fileno(log));  // вывод stdout в log
  perror("after dups");                             // вывод stderr в log
  fputs("2\n", log); fflush(log);                   // еще один прямой вывод в log
  dup2(save1, 1);  //  восстановим вывод stdout 
  dup2(save2, 2);  //  восстановим вывод stderr
  close(save1), close(save2);
  fputs("3\n", log); fflush(log);  // и еще один последний прямой вывод в log
  errno = 0;
  // здесь вывод ошибок пойдет уже в старый stderr (консоль)
  if (fclose(log))
    perror("fclose err");
  else
    perror("fclose OK");

  // выведем лог на экран (в старый stdout)
  log = fopen(av[1], "r");
  puts("Log:");
  int c;
  while ((c = fgetc(log)) != EOF)
    putchar(c);
  puts("--- end log ---");
  return puts("End") == EOF;
}

По крайней мере с консолью и stderr/stdout перенаправленными в обычные файлы, а также с конвейером ( ... | cat -n ) работает

avp@avp-xubu2:~/hashcode$ gcc tdup.c && ./a.out 1t
Go...
Start: Success
fclose OK: Success
Log:
1
dup2: 1  out: 3
after dups: Success
2
3
--- end log ---
End
avp@avp-xubu2:~/hashcode$ 
avp@avp-xubu2:~/hashcode$ 
avp@avp-xubu2:~/hashcode$ cat 1t
1
dup2: 1  out: 3
after dups: Success
2
3
avp@avp-xubu2:~/hashcode$ 
READ ALSO
Как уменьшить ошибку интерполяции на границах интервала

Как уменьшить ошибку интерполяции на границах интервала

Необходимо выполнить интерполяцию данных кубическим сплайномВсе вроде хорошо, но полиномы на концах имеют уж слишком большую ошибку

148
Блендинг в opencv

Блендинг в opencv

Есть задача: наложить одно изображение (png) на другое (фон, считаем, что альфаканал все время равен 1 (диапазон 0:1)) и так, чтобы пиксели смешались...

132