В упражнении 13.4 приведена программа popen4.c, которую можно использовать для демонстрации поведения popen. Вы можете сосчитать количество строк во всех файлах с исходным текстом примеров семейства popen, применив команду cat к файлам и затем пересылая по каналу вывод в команду wc -l, которая считает количество строк. В командной строке эквивалентная команда выглядит следующим образом:
$ cat popen*.c | wc -l
На самом деле wc -l popen*.c легче и гораздо эффективнее ввести с клавиатуры, но пример иллюстрирует основные принципы использования каналов.
popen запускает командную оболочкуЭта программа применяет в точности предыдущую команду, но с помощью popen, так что она может читать результат.
#include
#include
#include
#include
int main() {
FILE *read_fp;
char buffer[BUFSIZ +1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
read_fp = popen("cat popen*.с | wc -l", "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
while (chars_read > 0) {
buffer[chars_read - 1] = '\0';
printf("Reading:-\n %s\n", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
Выполнив эту программу, вы получите следующий вывод:
$ ./popen4
Reading:-
94
Как это работает
Программа показывает, что вызывается командная оболочка для того, чтобы развернуть popen*.с в список всех файлов, начинающихся с popen и заканчивающихся .с, а также для обработки символа канала (|) и отправки вывода команды cat в команду wс. Вы вызываете командную оболочку, программы cat и wc и задаете перенаправление — все в одном вызове popen. Программа, вызвавшая команду, видит только заключительный вывод.
Вызов
Вы познакомились с высокоуровневой функцией popen, а теперь пойдем дальше и рассмотрим низкоуровневую функцию pipe. Она предоставляет средства передачи данных между двумя программами без накладных расходов на вызов командной оболочки для интерпретации запрашиваемой команды. Эта функция также позволит вам лучше управлять чтением и записью данных.
У функции pipe следующее объявление:
#include
int pipe(int file_descriptor[2]);
Функции pipe передается указатель на массив из двух целочисленных файловых дескрипторов. Она заполняет массив двумя новыми файловыми дескрипторами и возвращает 0. В случае неудачи она вернет -1 и установит переменную errno для указания причины сбоя. В интерактивном справочном руководстве Linux на странице, посвященной функций pipe (в разделе 2 руководства), определены следующие ошибки:
□ EMFILE — процесс использует слишком много файловых дескрипторов;
□ ENFILE — системная таблица файлов полна;
□ EFAULT — некорректный файловый дескриптор.
Два возвращаемых файловых дескриптора подсоединяются специальным образом. Любые данные, записанные в file_descriptor[1], могут быть считаны обратно из file_descriptor[0]. Данные обрабатываются по алгоритму1, 2, 3 в file_descriptor[1], чтение из file_descriptor[0] выполняется в следующем порядке: 1, 2, 3. Этот способ отличается от стека, который функционирует по алгоритму
Важно уяснить, что речь идет о файловых дескрипторах, а не о файловых потоках, поэтому для доступа к данным вы должны применять низкоуровневые системные вызовы read и write вместо библиотечных функций потоков fread и fwrite.
В упражнении 13.5 приведена программа pipe1.с, которая использует вызов pipe для создания канала.
pipeСледующий пример — программа pipe1.c. Обратите внимание на массив file_pipes, который передается функции pipe как параметр.
#include
#include
#include
#include
int main() {
int data_processed;