• Между выполнением функций popen() и pclose() вызывающий процесс может создать других потомков, поэтому стандарт SUSv3 требует, чтобы вызов popen()
В листинге 44.5 показан пример использования функций popen() и pclose(). Программа многократно считывает шаблон имени файла
Листинг 44.5. Поиск файлов по шаблону с помощью функции popen()
pipes/popen_glob.c
#include
#include
#include "print_wait_status.h" /* Для printWaitStatus() */
#include "tlpi_hdr.h"
#define PAT_SIZE 50
#define PCMD_BUF_SIZE (sizeof(POPEN_FMT) + PAT_SIZE)
int
main(int argc, char *argv[])
{
char pat[PAT_SIZE]; /* Поиск по шаблону */
char popenCmd[PCMD_BUF_SIZE];
FILE *fp; /* Файловый поток, возвращенный вызовом popen() */
Boolean badPattern; /* Некорректные символы в 'pat'? */
int len, status, fileCnt, j;
char pathname[PATH_MAX];
for (;;) { /* Считываем шаблон, выводим результаты поиска */
printf("pattern: ");
fflush(stdout);
break; /* Конец файла */
len = strlen(pat);
if (len <= 1) /* Пустая строка */
continue;
if (pat[len — 1] == '\n') /* Убираем завершающий символ новой строки */
pat[len — 1] = '\0';
/* Следим за тем, чтобы шаблон содержал только допустимые символы, то есть
буквы, цифры, подчеркивания, точки и символы поиска по шаблону,
поддерживаемые командной оболочкой (мы используем более строгое
определение допустимого, чем командная оболочка, которая позволяет
добавлять любые символы, если они находятся внутри кавычек). */
if (!isalnum((unsigned char) pat[j]) &&
strchr("_*?[^-].", pat[j]) == NULL)
badPattern = TRUE;
if (badPattern) {
printf("Bad pattern character: %c\n", pat[j — 1]);
continue;
}
/* Создаем и выполняем команду glob 'pat' */
popenCmd[PCMD_BUF_SIZE — 1] = '\0'; /* Добавляем в конце строки
нулевой символ */
if (fp == NULL) {
printf("popen() failed\n");
continue;
}
/* Перебираем итоговый список путей, пока не доходим до конца файла */
fileCnt = 0;
while (fgets(pathname, PATH_MAX, fp)!= NULL) {
printf("%s", pathname);
fileCnt++;
}
/* Закрываем канал, извлекаем и выводим код завершения */
status = pclose(fp);
printf(" %d matching file%s\n", fileCnt,
(fileCnt!= 1)? "s": "");
printf(" pclose() status = %#x\n", (unsigned int) status);
if (status!= -1)
printWaitStatus("\t", status);
}
exit(EXIT_SUCCESS);
}
pipes/popen_glob.c
Использование программы из листинга 44.5 показано на примере следующей сессии командной строки. Здесь мы указываем два шаблона: первому соответствуют два файла, а для второго не находится ни одного совпадения:
$ ./popen_glob
pattern: popen_glob*
popen_glob
popen_glob.c
2 matching files
pclose() status = 0
child exited, status=0
pattern: x*
0 matching files
pclose() status = 0x100
child exited, status=1
pattern: ^D$
Построение команды поиска по шаблону
Стоит также обратить внимание на проверку ввода, производимую в листинге 44.5
pattern: ; rm *
В этом случае программа передала бы в функцию popen() следующую команду, что привело бы к катастрофическим результатам:
/bin/ls — d; rm * 2> /dev/null