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() запускает команды через системную оболочку и должна использоваться с большой осторожностью, если вызывается из программы со специальными полномочиями.