Литмир - Электронная Библиотека
Содержание  
A
A
Упражнение 13.4. Вызов
popen
запускает командную оболочку

Эта программа применяет в точности предыдущую команду, но с помощью

popen
, так что она может читать результат.

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

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);

}

Выполнив эту программу, вы получите следующий вывод:

$ <b>./popen4</b>

Reading:-

94

Как это работает

Программа показывает, что вызывается командная оболочка для того, чтобы развернуть

popen*.с
в список всех файлов, начинающихся с
popen
и заканчивающихся
, а также для обработки символа канала (
|
) и отправки вывода команды
cat
в команду
. Вы вызываете командную оболочку, программы
cat
и
wc
и задаете перенаправление — все в одном вызове
popen
. Программа, вызвавшая команду, видит только заключительный вывод.

Вызов pipe

Вы познакомились с высокоуровневой функцией

popen
, а теперь пойдем дальше и рассмотрим низкоуровневую функцию
pipe
. Она предоставляет средства передачи данных между двумя программами без накладных расходов на вызов командной оболочки для интерпретации запрашиваемой команды. Эта функция также позволит вам лучше управлять чтением и записью данных.

У функции

pipe
следующее объявление:

<b>#include &lt;unistd.h&gt;</b>

<b>int pipe(int file_descriptor[2]);</b>

Функции

pipe
передается указатель на массив из двух целочисленных файловых дескрипторов. Она заполняет массив двумя новыми файловыми дескрипторами и возвращает 0. В случае неудачи она вернет -1 и установит переменную
errno
для указания причины сбоя. В интерактивном справочном руководстве Linux на странице, посвященной функций
pipe
(в разделе 2 руководства), определены следующие ошибки:

□ 

EMFILE
— процесс использует слишком много файловых дескрипторов;

□ 

ENFILE
— системная таблица файлов полна;

□ 

EFAULT
— некорректный файловый дескриптор.

Два возвращаемых файловых дескриптора подсоединяются специальным образом. Любые данные, записанные в

file_descriptor[1]
, могут быть считаны обратно из
file_descriptor[0]
. Данные обрабатываются по алгоритму "первым пришел, первым обслужен", обычно обозначаемому как FIFO. Это означает, что если вы записываете байты
1
,
2
,
3
в
file_descriptor[1]
, чтение из
file_descriptor[0]
выполняется в следующем порядке:
1
,
2
,
3
. Этот способ отличается от стека, который функционирует по алгоритму "последним пришел, первым обслужен", который обычно называют сокращенно LIFO.

Примечание

Важно уяснить, что речь идет о файловых дескрипторах, а не о файловых потоках, поэтому для доступа к данным вы должны применять низкоуровневые системные вызовы

read
и
write
вместо библиотечных функций потоков
fread
и
fwrite
.

В упражнении 13.5 приведена программа pipe1.с, которая использует вызов

pipe
для создания канала.

Упражнение 13.5 Функция
pipe

Следующий пример — программа pipe1.c. Обратите внимание на массив

file_pipes
, который передается функции
pipe
как параметр.

#include &lt;unistd.h&gt;

#include &lt;stdlib.h&gt;

#include &lt;stdio.h&gt;

#include &lt;string.h&gt;

int main() {

 int data_processed;

 int filepipes[2];

 const char some_data[] = &quot;123&quot;;

 char buffer[BUFSIZ + 1];

 memset(buffer, '\0', sizeof(buffer));

 if (pipe(file_pipes) == 0) {

  data_processed = write(file_pipes[1], some_data, strlen(somedata));

  printf(&quot;Wrote %d bytes\n&quot;, data_processed);

  data_processed = read(file_pipes[0], buffer, BUFSIZ);

  printf(&quot;Read %d bytes: %s\n&quot;, data_processed, buffer);

231
{"b":"285844","o":1}