Читаем Linux API. Исчерпывающее руководство полностью

Ответ следующий: дублировать файловые дескрипторы, используя методики, описанные в разделе 5.5. Традиционно для достижения желаемого результата выполняется следующая цепочка вызовов:

int pfd[2];

pipe(pfd); /* Выделим для канала (к примеру) файловые дескрипторы 3 и 4 */

/* Здесь выполняем другие шаги, например fork() */

close(STDOUT_FILENO); /* Освобождаем файловый дескриптор 1 */

dup(pfd[1]); /* При дублировании используется наименьший

свободный номер дескриптора, то есть fd 1 */

Конечным результатом вышеприведенных шагов является то, что стандартный вывод процесса привязывается к записывающему концу канала. Аналогичная цепочка вызовов применяется для привязки считывающего конца канала к стандартному вводу процесса.

Стоит отметить: данные шаги основаны на предположении о том, что файловые дескрипторы процесса с номерами 0, 1 и 2 уже открыты (командная оболочка обычно делает это автоматически для каждой программы, которая в ней выполняется). Если бы дескриптор 0 был закрыт до вышеприведенных вызовов, то мы бы ошибочно привязали к записывающему концу канала стандартной ввод процесса. Чтобы исключить такую возможность, close() и dup() можно заменить вызовом dup2(), показанным ниже; это позволит нам явно задать дескриптор, который будет привязан к концу канала:

dup2(pfd[1], STDOUT_FILENO); /* Закрываем дескриптор 1 и повторно устанавливаем

связь с записывающим концом канала */

Продублировав pfd[1], мы получили два дескриптора, ссылающихся на записывающий конец канала: дескриптор 1 и pfd[1]. Поскольку неиспользуемые файловые дескрипторы канала следует закрывать, мы сделаем это после вызова dup2():

close(pfd[1]);

Код, показанный выше, требует предварительного открытия стандартного вывода. Предположим, что стандартный ввод/вывод был закрыт перед вызовом pipe(). В этом случае вызов pipe() выделил бы для канала два дескриптора — например, pfd[0] со значением 0 и pfd[1] со значением 1. Следовательно, эквивалентом предыдущих вызовов dup2() и close() был бы такой код:

dup2(1, 1); /* Ничего не делает */

close(1); /* Закрывает единственный дескриптор для записывающего конца канала */

В целях безопасности эти вызовы рекомендуется заключить внутрь инструкции if следующего вида:

if (pfd[1]!= STDOUT_FILENO) {

dup2(pfd[1], STDOUT_FILENO);

close(pfd[1]);

}

Пример программы

Программа, представленная в листинге 44.4, использует методики, описанные в данном разделе для получения того же результата, что и у кода из листинга 44.1. Открыв канал, мы создаем два дочерних процесса. Первый привязывает свой стандартный вывод к записывающему концу канала, после чего выполняет команду ls. Второй привязывает свой стандартный ввод к считывающему концу канала и выполняет команду wc.

Листинг 44.4. Использование канала для соединения команд ls и wc

pipes/pipe_ls_wc.c

#include

#include "tlpi_hdr.h"

int

main(int argc, char *argv[])

{

int pfd[2]; /* Файловые дескрипторы канала */

if (pipe(pfd) == -1) /* Создаем канал */

errExit("pipe");

switch (fork()) {

case -1:

errExit("fork");

case 0: /* Первый потомок выполняет 'ls', записывая результат в канал */

if (close(pfd[0]) == -1) /* Считывающий конец не используется */

errExit("close 1 ");

/* Дублируем стандартный вывод на записывающем конце канала;

закрываем лишний дескриптор */

if (pfd[1]!= STDOUT_FILENO) { /* Проверка на всякий случай */

if (dup2(pfd[1], STDOUT_FILENO) == -1)

errExit("dup2 1");

if (close(pfd[1]) == -1)

errExit("close 2");

}

execlp("ls", "ls", (char *) NULL); /* Записывает в канал */

errExit("execlp ls");

default: /* Родитель выходит из этого блока, чтобы создать следующего потомка */

break;

}

switch (fork()) {

case -1:

errExit("fork");

case 0: /* Второй потомок выполняет 'wc', считывая ввод из канала */

if (close(pfd[1]) == -1) /* Записывающий конец не используется */

errExit("close 3");

/* Дублируем стандартный ввод на считывающем конце канала;

закрываем лишний дескриптор */

if (pfd[0]!= STDIN_FILENO) { /* Проверка на всякий случай */

if (dup2(pfd[0], STDIN_FILENO) == -1)

errExit("dup2 2");

if (close(pfd[0]) == -1)

errExit("close 4");

}

execlp("wc", "wc", "-l", (char *) NULL); /* Читает из канала */

errExit("execlp wc ");

default: /* Родитель выходит из этого блока */

break;

}

/* Родитель закрывает лишние дескрипторы канала и ждет завершения дочерних процессов */

if (close(pfd[0]) == -1)

errExit("close 5");

if (close(pfd[1]) == -1)

errExit("close 6");

if (wait(NULL) == -1)

errExit("wait 1");

if (wait(NULL) == -1)

errExit("wait 2");

exit(EXIT_SUCCESS);

}

pipes/pipe_ls_wc.c

Запустив программу из листинга 44.4, мы увидим следующее:

$ ./pipe_ls_wc

24

$ ls | wc — l Проверяем результаты с помощью консольных команд

24

44.5. Взаимодействие с консольными командами с помощью канала: popen()
Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных