практические примеры использования dup или dup2 - PullRequest
62 голосов
/ 12 ноября 2009

Я знаю, что делает dup / dup2, но понятия не имею, когда это будет использовано.

Какие-нибудь практические примеры?

Спасибо.

Ответы [ 5 ]

59 голосов
/ 12 ноября 2009

Одним из примеров использования будет перенаправление ввода / вывода. Для этого вы разветвляете дочерний процесс и закрываете дескрипторы файлов stdin или stdout (0 и 1), а затем выполняете dup () для другого файлового дескриптора по вашему выбору, который теперь будет сопоставлен с наименьшим доступным дескриптором файла, который находится в этом случай 0 или 1.

Используя это, вы теперь можете запускать любой дочерний процесс, который, возможно, не знает о вашем приложении, и всякий раз, когда ребенок записывает в стандартный вывод (или читает из стандартного ввода, независимо от того, что вы настроили), вместо этого данные записываются в предоставленный дескриптор файла.

Оболочки используют это для реализации команд с каналами, например /bin/ls | more, подключив стандартный вывод одного процесса к стандартному другому.

22 голосов
/ 12 февраля 2015

Лучший сценарий для понимания dup и dup2 - это перенаправление.
Первое, что нам нужно знать, - это то, что система имеет 3 идентификатора файла по умолчанию (или переменных, указывающих выходные данные или источники ввода), которые имеют дело с вводом и выводом. Они stdin, stdout, stderr, в целых числах они 0, 1, 2. Большинство функций, таких как fprintf или cout, напрямую выводятся на stdout.
Если мы хотим перенаправить вывод, одним из способов является, например, дать fprintf функцию побольше аргументов, указывающих in и out.
Однако есть более элегантный способ: мы можем перезаписать идентификаторы файлов по умолчанию, чтобы они указывали на файл, который мы хотим получить на выходе. dup и dup2 точно работают в этой ситуации.
Давайте начнем с одного простого примера: предположим, мы хотим перенаправить вывод fprintf в текстовый файл с именем "chinaisbetter.txt". Прежде всего нам нужно открыть этот файл

int fw=open("chinaisbetter.txt", O_APPEND|O_WRONLY);

Затем мы хотим, чтобы stdout указывал на "chinaisbetter.txt" с помощью функции dup:

dup2(fw,1);

Теперь stdout (1) указывает на дескриптор "chinaisbetter.txt", хотя он все еще равен 1, но вывод перенаправлен.
Тогда вы можете использовать printf как обычно, но результаты будут в текстовом файле, а не показываться непосредственно на экране:

printf("Are you kidding me? \n");

PS

  1. Это просто дает интуитивное объяснение, вам может понадобиться проверить справочную страницу или подробную информацию. На самом деле, мы говорим «копировать», они не копируют все.

  2. Идентификатор файла здесь ссылается на обработчик файла. Упомянутый выше дескриптор файла является структурой информации файла записей.

9 голосов
/ 12 ноября 2009

Если вам интересны функции POSIX, особенно те, которые, кажется, дублируют друг друга, обычно хорошо проверить сам стандарт . Внизу вы обычно увидите примеры, а также рассуждения о реализации (и существовании) обоих.

В этом случае:

Следующие разделы являются информативными.

Примеры

Перенаправление стандартного вывода в файл

Следующий пример закрывает стандартный вывод для текущих процессов, переназначает стандартный вывод для перехода к файлу, на который ссылается pfd, и закрывает исходный дескриптор файла для очистки.

#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...

Перенаправление сообщений об ошибках

В следующем примере перенаправляются сообщения с stderr на stdout.

#include <unistd.h>
...
dup2(2, 1); // 2-stderr; 1-stdout
...

Использование приложения

Отсутствует.

Обоснование

Функции dup() и dup2() являются избыточными. Их услуги также предоставляются функцией fcntl(). Они были включены в этот том IEEE Std 1003.1-2001 в основном по историческим причинам, так как многие существующие приложения используют их.

Хотя показанный сегмент краткого кода очень похож по поведению на dup2(), соответствующая реализация, основанная на других функциях, определенных в этом томе IEEE Std 1003.1-2001, значительно сложнее. Наименее очевидным является возможный эффект функции перехвата сигнала, которая может вызываться между шагами и выделять или освобождать файловые дескрипторы. Этого можно избежать, блокируя сигналы.

Функция dup2() не помечена как устаревшая, поскольку она представляет безопасную от типов версию функциональности, предоставленную в небезопасной версии с помощью fcntl(). Используется в привязке POSIX Ada.

Функция dup2() не предназначена для использования в критических областях в качестве механизма синхронизации.

В описании [EBADF] случай, когда файлы находятся вне диапазона, охватывается данным случаем, когда файлы не являются действительными. Описания для fildes и fildes2 различны, потому что единственный тип недействительности, который имеет отношение к fildes2, - находится ли он вне диапазона; то есть не имеет значения, относится ли fildes2 к открытому файлу при выполнении вызова dup2().

Будущие направления

Отсутствует.

Смотри также

close(), fcntl(), open(), том Базовых определений IEEE Std 1003.1-2001, <unistd.h>

История изменений

Впервые выпущено в выпуске 1. Получено из выпуска 1 SVID.

5 голосов
/ 12 ноября 2009

Одним из практических примеров является перенаправление выходных сообщений в какой-то другой поток, например, в некоторый файл журнала. Вот пример кода для перенаправления ввода / вывода.
Пожалуйста, обратитесь к оригинальному сообщению здесь

#include <stdio.h>

main()
{
    int    fd;
    fpos_t pos;

    printf("stdout, ");

    fflush(stdout);
    fgetpos(stdout, &pos);
    fd = dup(fileno(stdout));
    freopen("stdout.out", "w", stdout);

    f();

    fflush(stdout);
    dup2(fd, fileno(stdout));
    close(fd);
    clearerr(stdout);
    fsetpos(stdout, &pos);        /* for C9X */

    printf("stdout again\n");
}

f()
{
printf("stdout in f()");
}
1 голос
/ 21 июня 2018

Перенаправление ввода / вывода в оболочке, скорее всего, будет реализовано с помощью системных вызовов dup2 / fcnlt.

Мы можем легко эмулировать тип перенаправления $program 2>&1 > logfile.log, используя функцию dup2.

Программа ниже перенаправляет как stdout, так и stderr .i.e имитирует поведение $program 2>&1 > output с использованием dup2.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int
main(void){
    int close_this_fd;
    dup2(close_this_fd = open("output", O_WRONLY), 1);
    dup2(1,2);
    close(close_this_fd);
    fprintf(stdout, "standard output\n");
    fprintf(stderr, "standard error\n");
    fflush(stdout);
    sleep(100); //sleep to examine the filedes in /proc/pid/fd level.
    return;
}

vagrant@precise64:/vagrant/advC$ ./a.out
^Z
[2]+  Stopped                 ./a.out
vagrant@precise64:/vagrant/advC$ cat output
standard error
standard output
vagrant@precise64:/vagrant/advC$ ll /proc/2761/fd
total 0
dr-x------ 2 vagrant vagrant  0 Jun 20 22:07 ./
dr-xr-xr-x 8 vagrant vagrant  0 Jun 20 22:07 ../
lrwx------ 1 vagrant vagrant 64 Jun 20 22:07 0 -> /dev/pts/0
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 1 -> /vagrant/advC/output
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 2 -> /vagrant/advC/output
...