Книга: Linux программирование в примерах
12.7.2. Раскрытие имени файла: glob() и globfree()
12.7.2. Раскрытие имени файла: glob()
и globfree()
Функции glob()
и globfree()
более разработанные, чем fnmatch()
:
#include <glob.h> /* POSIX */
int glob(const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno), glob_t *pglob);
void globfree(glob_t *pglob);
Функция glob()
осуществляет просмотр каталога и сопоставление с шаблонами, возвращая список всех путей, соответствующих pattern
. Символы подстановки могут быть включены в нескольких местах пути, а не только в качестве последнего компонента (например, '/usr/*/*.so
'). Аргументы следующие:
const char *pattern
Шаблон для раскрывания.
int flags
Флаги, управляющие поведением glob()
, вскоре будут описаны.
int (*errfunc)(const char *epath, int eerrno)
Указатель на функцию для использования при сообщениях об ошибках. Это значение может равняться NULL
. Если нет и если (*errfunc)()
возвращает ненулевое значение или в flags
установлен GLOB_ERR
, glob()
прекращает обработку. Аргументами (*errfunc)()
являются путь, вызвавший проблему, и значение errno, установленное функциями opendir()
, readdir()
или stat()
.
glob_t *pglob
Указатель на структуру glob_t
, использующуюся для хранения результатов. Структура glob_t
содержит список путей, которые выдает glob()
:
typedef struct { /* POSIX */
size_t gl_pathc; /* Число найденных подходящих путей */
char **gl_pathv; /* Список подходящих путей */
size_t gl_offs; /* Слоты для резервирования в gl_pathv */
} glob_t;
size_t gl_pathc
Число путей, которые подошли.
char **gl_pathv
Массив подходящих путей. gl_pathv[gl_pathc]
всегда равен NULL
.
size_t gl_offs
«Зарезервированные слоты» в gl_pathv
. Идея заключается в резервировании слотов спереди от gl_pathv
для заполнения их приложением впоследствии, как в случае с именем команды и опциями. Список затем может быть передан непосредственно execv()
или execvp()
(см. раздел 9.1.4 «Запуск новой программы: семейство exec()
»). Зарезервированные слоты устанавливаются в NULL
. Чтобы все это работало, в flags
должен быть установлен GLOB_DOOFFS
.
В табл. 12.2 перечислены стандартные флаги для glob()
.
Таблица 12.2. Флаги для glob()
Флаг | Значение |
---|---|
GLOB_APPEND |
Добавить результаты текущего вызова к предыдущим |
GLOB_DOOFFS |
Зарезервировать места gl_offs спереди в gl_pathv |
GLOB_MARK |
Добавлять символ / в конец каждого имени, которое обозначает каталог |
GLOB_NOCHECK |
Если шаблон не соответствует имени какого-нибудь файла, вернуть его без изменений |
GLOB_NOESCAPE |
Рассматривать обратный слеш как обычный символ. Это делает невозможным обозначать метасимволы подстановок |
GLOB_NOSORT |
Не сортировать результаты, по умолчанию они сортируются |
GLIBC версия структуры glob_t
содержит дополнительные члены:
typedef struct { /* GLIBC */
/* Компоненты POSIX: */
size_t gl_pathc; /* Число подходящих путей */
char **gl_pathv; /* Список подходящих путей */
size_t gl_offs; /* Резервируемые в gl_pathv слоты */
/* Компоненты GLIBC: */
int gl_flags; /* Копия флагов, дополнительные флаги GLIBC */
void (*gl_closedir)(DIR *); /* Частная версия closedir() */
struct dirent *(*gl_readdir)(DIR *); /* Частная версия readdir)) */
DIR *(*gl_opendir)(const char *); /* Частная версия opendir)) */
int (*gl_lstat)(const char *, struct stat *);
/* Частная версия lstat() */
int (*gl_stat)(const char *, struct stat *); /* Частная версия stat() */
} glob_t;
Члены структуры следующие:
int gl_flags
Копия флагов. Включает также GLOB_MAGCHAR
, если pattern
включал какие-либо метасимволы.
void (*gl_closedir)(DIR *)
Указатель на альтернативную версию closedir()
.
struct dirent *(*gl_readdir)(DIR *)
Указатель на альтернативную версию readdir()
.
DIR *(*gl_opendir)(const char *)
Указатель на альтернативную версию opendir()
.
int (*gl_lstat)(const char *, struct stat*)
Указатель на альтернативную версию lstat()
.
int (*gl_stat)(const char*, struct stat*)
Указатель на альтернативную версию stat()
.
Указатели на альтернативные версии стандартных функций предназначены главным образом для использования в реализации GLIBC; крайне маловероятно, что вы когда-нибудь их используете. Поскольку GLIBC предусматривает поле gl_flags
и дополнительные значения флагов, справочная страница и руководство Info документируют оставшуюся часть структуры GLIBC glob_t
. В табл. 12.3 перечислены дополнительные флаги.
Таблица 12.3. Дополнительные флаги GLIBC для glob()
Флаг | Значение |
---|---|
GLOB_ALTDIRFUNC |
Использовать для доступа к каталогам альтернативные функции (см. текст) |
GLOB_BRACE |
Выполнить раскрытие фигурных скобок в стиле csh и Bash. |
GLOB_MAGCHAR |
Вставить gl_flags , если были найдены метасимволы. |
GLOB_NOMAGIC |
Вернуть шаблон, если он не содержит метасимволов |
GLOB_ONLYDIR |
По возможности сопоставлять лишь каталоги. См. текст. |
GLOB_PERIOD |
Разрешить соответствие метасимволов наподобие * и ? начальной точке |
GLOB_TILDE |
Выполнить раскрывание тильды в стиле оболочки. |
GLOB_TILDE_CHECK |
Подобно GLOB_TILDE , но если есть проблемы с указанным домашним каталогом, вернуть GLOB_NOMATCH вместо помещения pattern в список. |
Флаг GLOB_ONLYDIR
действует в качестве подсказки реализации, потому что вызывающий интересуется лишь каталогами. Главным его предназначением является использование другими функциями в GLIBC, а вызывающий по-прежнему должен быть готов обрабатывать файлы, не являющиеся каталогами. Вам не следует использовать этот флаг в своих программах.
glob()
может быть вызвана более одного раза: при первом вызове флаг GLOB_APPEND
не должен быть указан, при всех последующих вызовах он должен быть указан. Вы не можете между вызовами изменять gl_offs
, а если вы изменили какие-нибудь значения в gl_pathv
или gl_pathc
, нужно их восстановить перед последующим вызовом glob()
.
Возможность многократного вызова glob()
позволяет накапливать результаты в одном списке. Это довольно практично, приближается к мощным возможностям раскрывания групповых символов оболочки, но на уровне языка программирования С.
glob()
возвращает 0, если не было проблем, или одно из значений из табл. 12.4, если были.
Таблица 12.4. Возвращаемые glob()
значения
Флаг | Значение |
---|---|
GLOB_ABORTED |
Просмотр остановлен раньше времени, поскольку был установлен GLOB_ERR или функция (*errfunc)() возвратила ненулевой результат |
GLOB_NOMATCH |
Ни одно имя файла не соответствовало pattern , а флаг GLOB_NOCHECK не был установлен |
GLOB_NOSPACE |
Была проблема с выделением динамической памяти |
globfree()
освобождает всю память, которую динамически выделила glob()
Следующая программа, ch12-glob.с
, демонстрирует glob()
:
1 /* ch12-glob.c --- демонстрирует glob(). */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <glob.h>
6
7 char *myname;
8
9 /* globerr --- выводит сообщение об ошибке для glob() */
10
11 int globerr(const char *path, int eerrno)
12 {
13 fprintf(stderr, "%s: %s: %sn", myname, path, strerror(eerrno));
14 return 0; /* let glob() keep going */
15 }
16
17 /* main() --- раскрывает символы подстановки в командной строке и выводит результаты */
18
19 int main(int argc, char **argv)
20 {
21 int i;
22 int flags = 0;
23 glob_t results;
24 int ret;
25
26 if (argc == 1) {
27 fprintf(stderr, "usage: %s wildcard ...n", argv[0]);
28 exit(1);
29 }
30
31 myname = argv[0]; /* для globerr() */
32
33 for (i = 1; i < argc; i++) {
34 flags |= (i > 1 ? GLOB_APPEND : 0);
35 ret = glob(argv[i], flags, globerr, &results);
36 if (ret != 0) {
37 fprintf(stderr, "%s: problem with %s (%s),
38 stopping earlyn", myname, argv[i],
39 /* опасно: */ (ret == GLOB_ABORTED ? "filesystem problem" :
40 ret == GLOB_NOMATCH ? "no match of pattern" :
41 ret == GLOB_NOSPACE ? "no dynamic memory" :
42 "unknown problem"));
43 break;
44 }
45 }
46
47 for (i = 0; i < results.gl_pathc; i++)
48 printf("%sn", results.gl_pathv[i]);
49
50 globfree(&results);
51 return 0;
52 }
Строка 7 определяет myname
, которая указывает на имя программы; эта переменная для сообщений об ошибках от globerr()
, определенной в строках 11–15.
Строки 33–45 являются основой программы. Они перебирают в цикле шаблоны, приведенные в командной строке, вызывая для каждого glob()
для добавления к списку результатов. Большую часть цикла составляет обработка ошибок (строки 36–44). Строки 47–48 выводят результирующий список, а строки 50–51 проводят завершающую очистку и возвращаются.
Строки 39–41 не являются хорошими; нужно было использовать отдельную функцию, преобразующую целые константы в строки; мы сделали это главным образом ради экономии места. Код наподобие этого может быть сносным для небольших программ, но более крупные должны использовать функцию.
Если вы подумаете о работе, происходящей под капотом (открытие и чтение каталогов, сопоставление шаблонов, динамическое выделение памяти для увеличения списка, сортировка списка), можете качать ценить, как много для вас делает glob()
! Вот некоторые результаты:
$ ch12-glob '/usr/lib/x*.so' '../../*.texi'
/usr/lib/xchat-autob5.so
/usr/lib/xchat-autogb.so
../../00-preface.texi
../../01-intro.texi
../../02-cmdline.texi
../../03-memory.texi
...
Обратите внимание, что нам пришлось взять аргументы в кавычки, чтобы предотвратить их разворачивание оболочкой!
Универсализация имен? Что это?
В былые времена, около V6 Unix, для осуществления разворачивания символов подстановки оболочка использовала за кулисами отдельную программу. Эта программа называлась /etc/glob
, и согласно исходному коду V6[130], имя «glob» было сокращением от «global».
Таким образом глагол «to glob» проник в лексикон Unix со значением «осуществлять разворачивание символов подстановки». Это, в свою очередь, дает нам имена функций glob()
и globfree()
. Так что обычно недооцениваемое чувство юмора, время от времени проглядывающее из руководства Unix, все еще живо, официально сохраненное в стандарте POSIX. (Можете ли вы представить кого-нибудь в IBM в 70-х или 80-х годах XX века, называющего системную процедуру glob()
?)
- Эффективная работа с временными файлами сортировки
- Единое имя файла параметров InterBase
- Параметры конфигурационного файла InterBase
- 13. Зарабатываем на своих файлах: файлообменники, загружаеми получаем процент за скачивание
- Листинг 15.11. Код для загрузки файла с Web-сервера
- Создание и открытие файла
- Управление файлами занятий
- 8.8.11. Мероприятие 12: Раскрытие информации о механизмах агрессивного налогового планирования
- Получение доменного имени
- Как изменить имя файла или папки?
- Как создавать комментарии к файлам?
- Что такое расширение файла? Откуда Windows знает, какой программой открывать файл?