10.5.2. Чтение и запись из процесса

10.5.2. Чтение и запись из процесса

Хотя system() отображает результат работы команды на устройство стандартного вывода и позволяет дочерним программам читать стандартный ввод, это не всегда идеально. Часто процесс желает читать вывод другого процесса либо отправлять текст на стандартный ввод. popen() облегчает процессам решение этой задачи[29].

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

cmd выполняется через оболочку, как и в system(). Параметр mode должен быть "r", если родительский процесс желает читать командный вывод, и "w" — для записи в стандартный ввод дочернего процесса. Следует отметить, что с помощью popen() делать одновременно чтение и запись нельзя.

Два процесса, которые читают и пишут друг в друга, достаточно сложны[30] и выходят за рамки возможностей popen()[31].

popen() возвращает FILE* (как это определено в стандартной библиотеке ввода-вывода ANSI/ISO), который может быть прочитан и записан подобно любому другому потоку stdio[32], либо NULL, если операция не удается. Когда завершается родительский процесс, он может воспользоваться pclose() для закрытия потока и прерывания дочернего процесса, если он все еще выполняется. Подобно system(), pclose() возвращает состояние дочернего процесса из wait4().

int pclose(FILE *stream);

Ниже приведен пример простой программы-калькулятора, которая использует программу bc для выполнения всей реальной работы. Важно сбрасывать поток, полученный от popen(), после записи в него, чтобы предотвратить буферизацию stdio от задержки вывода (подробности о буферизации стандартных функций библиотеки stdio можно найти в [15]).

 1: /*calc.c*/

 2:

 3: /* Это очень простой калькулятор, который использует внешнюю команду bc

 4:    для выполнения всей работы. Открывает канал к bc, читает команду,

 5:    передает ее bc и завершается. */

 6: #include <stdio.h>

 7: #include <sys/wait.h>

 8: #include <unistd.h>

 9:

10: int main(void) {

11:  char buf[1024];

12:  FILE *bc;

13:  int result;

14:

15:  /* открыть канал на bc и выйти в случае неудачи */

16:  bc = popen("bc", "w");

17:  if (!bc) {

18:   perror("popen");

19:   return 1;

20:  }

21:

22:  /* пригласить ввести выражение, и прочитать его */

23:  printf("expr:"); fflush(stdout);

24:  fgets(buf, sizeof(buf), stdin);

25:

26:  /* послать выражение bc для вычисления */

27:  fprintf(bc, "%s ", buf);

28:  fflush(bc);

29:

30:  /* закрыть канал на bc и ожидать выхода из нее */

31:  result = pclose(bc);

32:

33:  if (!WIFEXITED(result))

34:   printf("(аварийный выход) ");

35:

36:  return 0;

37: }

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