Повторное открытие файловых дескрипторов stdout и stdin после их закрытия - PullRequest
30 голосов
/ 31 января 2012

Я пишу функцию, которая при заданном аргументе либо перенаправит стандартный вывод в файл, либо прочитает стандартный вывод из файла. Для этого я закрываю файловый дескриптор, связанный с stdout или stdin, чтобы при открытии файла он открывался под дескриптором, который я только что закрыл. Это работает, но проблема в том, что, как только это будет сделано, мне нужно восстановить stdout и stdin до того, что они должны быть на самом деле.

То, что я могу сделать для stdout, открыто ("/ dev / tty", O_WRONLY); Но я не уверен, почему это работает, и что более важно, я не знаю эквивалентного утверждения для stdin.

Итак, у меня есть, для стандартного вывода

close(1);
if (creat(filePath, O_RDWR) == -1)
{
    exit(1);
}

и для стандартного ввода

close(0);
if (open(filePath, O_RDONLY) == -1)
{
    exit(1);
}

Ответы [ 3 ]

40 голосов
/ 31 января 2012

Вы должны использовать dup () и dup2 () для клонирования файлового дескриптора.

int stdin_copy = dup(0);
int stdout_copy = dup(1);
close(0);
close(1);

int file1 = open(...);
int file2 = open(...);

< do your work. file1 and file2 must be 0 and 1, because open always returns lowest unused fd >

close(file1);
close(file2);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);

Однако, есть небольшая деталь, с которой вы, возможно, захотите быть осторожным (от man dup):

Два дескриптора не разделяют флаги дескриптора файла ( крупный на execflag). Флаг закрытия при исполнении (FD_CLOEXEC; см. Fcntl (2)) дубликат дескриптора выключен.

Если это проблема, вам может потребоваться восстановить флаг close-on-exec, возможно, используя dup3 () вместо dup2 (), чтобы избежать условий гонки.

Также имейте в виду, что если ваша программа многопоточная, другие потоки могут случайно записать / прочитать ваш переназначенный stdin / stdout.

17 голосов
/ 31 января 2012

Я думаю, что вы можете "сохранить" дескрипторы перед перенаправлением :

int save_in, save_out;

save_in = dup(STDIN_FILENO);
save_out = dup(STDOUT_FILENO);

Позже вы можете использовать dup2 для их восстановления:

/* Time passes, STDIN_FILENO isn't what it used to be. */
dup2(save_in, STDIN_FILENO);

В этом примере я не проверяю ошибки - вам следует.

1 голос
/ 07 сентября 2015

Вы можете создать дочерний процесс и настроить перенаправление только внутри дочернего процесса. Затем подождите, пока ребенок завершит работу, и продолжите работу в родительском процессе. Таким образом, вам не нужно беспокоиться об отмене перенаправления.

Просто найдите примеры кода с использованием fork () и wait ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...