Строки 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()
?)
12.7.3. Разворачивание слов оболочкой: wordexp()
и wordfree()
Многие члены комитета POSIX чувствовали, что glob()
делает недостаточно: им нужна была библиотечная процедура, способная делать все, что может делать оболочка разворачивание тильды ('echo ~arnold
'), разворачивание переменных оболочки ('echo $HOME
') и подстановку команд ('echo $(cd ; pwd)
'). Многие другие чувствовали, что glob()
не подходила для этой цели. Чтобы «удовлетворить» каждого, POSIX предоставляет две дополнительные функции, которые делают все:
#include
int wordexp(const char *words, wordexp_t *pwordexp, int flags);
void wordfree(wordexp_t *wordexp);
Эти функции работают сходным с glob()
и globfree()
образом, но со структурой wordexp_t
:
typedef struct {
size_t we_wordc; /* Число подходящих слов */
char **we_wordv; /* Список развернутых слов */
size_t we_offs; /* Резервируемые в we_wordv слоты */
} wordexp_t;
Члены структуры полностью аналогичны описанным ранее для glob_t
; мы не будем здесь повторять все описание.
Как и для glob()
, поведение wordexp()
управляется несколькими флагами. Флаги перечислены в табл. 12.5.
Таблица 12.5. Флаги для wordexp()
Константа | Значение |
---|---|
WRDE_APPEND | Добавить результаты текущего вызова к предыдущим |
WRDE_DOOFFS | Зарезервировать we_offs мест в начале we_wordv |
WRDE_NOCMD | Запретить подстановку команд |
WRDE_REUSE | Повторно использовать память, на которую указывает we_wordv |
WRDE_SHOWERR | Не молчать при возникновении во время разворачивания ошибок |
WRDE_UNDEF | Неопределенные переменные оболочки должны вызывать ошибку |
Возвращаемое значение равно 0, если все прошло хорошо, или одно из значений из табл. 12.6, если нет.
Таблица 12.6. Возвращаемые значения ошибок для wordexp()