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

Каналы часто используют для выполнения консольных команд — в частности, для считывания их вывода или передачи им какого-нибудь ввода. Для упрощения этой задачи предусмотрены функции popen() и pclose():

#include

FILE *popen(const char *command, const char *mode);

Возвращает файловый поток или NULL, если произошла ошибка

int pclose(FILE *stream);

Возвращает код завершения дочернего процесса или -1, если произошла ошибка

Функция popen() открывает канал и создает дочерний процесс, запускающий командную оболочку, которая, в свою очередь, создает еще один дочерний процесс для выполнения строки, переданной в аргументе command. Аргумент mode представляет собой строку, определяющую, будет ли процесс читать из канала (mode равен r) или записывать в него (mode равен w). Это взаимоисключающие режимы, поскольку каналы являются однонаправленными. В зависимости от значения аргумента mode происходит одно из двух: либо стандартный вывод выполняемой команды соединяется с записывающим концом канала, либо ее стандартный ввод соединяется со считывающим концом канала (рис. 44.4).

Рис. 44.4. Общая схема взаимодействия процессов и применения канала с помощью вызова popen()

При успешном выполнении popen() возвращает указатель на файловый поток, который можно применять в библиотечных функциях стандартного ввода/вывода. При возникновении ошибки (например, когда значение mode не равно r или w, не удалось открыть канал или вызов fork(), создающий потомков, завершился неудачей) popen() возвращает NULL и устанавливает значение errno, чтобы сигнализировать о причине ошибки.

После завершения popen() вызывающий процесс использует канал для чтения вывода команды command или для передачи ей какого-нибудь ввода. Когда команда закрывает записывающий конец канала, вызывающий процесс получает символ конца файла (аналогично ведут себя каналы, созданные с помощью вызова pipe()). Если команда закрывает считывающий конец канала, то процесс получает сигнал SIGPIPE и ошибку EPIPE.

По окончании ввода/вывода вызывается функция pclose(), закрывающая канал и ждущая завершения дочерней командной оболочки (функция fclose() в этом случае не подходит, так как не ждет завершения потомка). В случае успеха pclose() возвращает код завершения (см. раздел 26.1.3) дочерней командной оболочки (который равен коду завершения последней выполненной в нем команды — если только оболочка не была завершена по сигналу). Как и в случае с вызовом system() (см. раздел 27.6), если командная оболочка не может быть запущена, то функция pclose() возвращает такое же значение, как если бы оболочка была закрыта с помощью вызова _exit(127). В случае возникновения какой-то другой ошибки pclose() возвращает -1. Возможна также ситуация, в которой не удается получить код завершения. Чуть ниже мы объясним, как это может произойти.

Стандарт SUSv3 требует, чтобы во время ожидания кода завершения дочерней командной оболочки функция pclose(), как и system(), автоматически перезапускала вызов waitpid(), который она выполняет внутри, если тот был прерван обработчиком сигнала.

В целом все написанное нами в разделе 27.6 относительно вызова system() применимо и к функции popen(). Она всего лишь предоставляет больше удобств: открывает канал, дублирует дескрипторы, закрывает те из них, что не используются, а также берет на себя все нюансы запуска вызовов fork() и exec(). Кроме того, команда управляется оболочкой. Но за такое удобство приходится платить производительностью, ведь для этого создается два дополнительных процесса: один для оболочки, а другой — для одной или нескольких команд, которые она выполняет. По аналогии с system() функция popen() никогда не должна вызываться из привилегированных программ.

Вызов system() и функции popen() и pclose() имеют определенное сходство, однако между ними существуют и различия. Оно вытекает из того факта, что system() инкапсулирует выполнение консольных команд внутри единого вызова, тогда как в случае с popen() вызывающий процесс работает параллельно консольной команде, после чего вызывает pclose(). Разница заключается в аспектах, представленных ниже.

• Поскольку вызывающий процесс и выполняемая команда работают параллельно, стандарт SUSv3 требует, чтобы функция popen() не игнорировала сигналы SIGINT и SIGQUIT. Если они сгенерированы с помощью клавиатуры, их получает как вызывающий процесс, так и выполняемая команда. Это вызвано тем, что оба процесса находятся в одной и той же группе, а, как мы знаем из раздела 34.5, сигналы, сгенерированные терминалом, получают все участники (активной) группы процессов.

Перейти на страницу:

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

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

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

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

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

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

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

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