Регулярные выражения являются важной частью Unix. Чтобы научиться заменять, вырезать и распределять текст с использованием регулярных выражений, мы рекомендуем эту книгу
7. Руководство для GNU
grep
также объясняет регулярные выражения. На системе GNU/Linux для просмотра локальной копии вы можете использовать '
info grep
'. Или использовать браузер для прочтения онлайн-документации проекта GNU для
grep
.
[135]
12.10. Резюме
• Операторы проверки предоставляют способ сделать утверждения о предполагаемом состоянии программы. Они являются полезным инструментом для проектирования и отладки и обычно должны оставаться в коде изделия. Однако, будьте внимательны, чтобы не перепутать операторы проверки с проверками возможных ошибок времени исполнения.
• Функции
mem<i>XXX</i>()
являются аналогичными более известным функциям
str<i>XXX</i>()
. Самой большой их ценностью является то. что они могут работать с двоичными данными; нулевые байты не отличаются от других байтов. Больше известна
memcpy()
против
memmove()
, обрабатывающей перекрывающиеся копии.
• Временные файлы полезны во многих приложениях. Функции API
tmpfile()
и
mkstemp()
являются предпочтительными способами создания временных файлов, в то же время позволяя избежать состояния гонки и связанных с ней проблем безопасности. Многие программы для указания местоположения своих временных файлов используют переменную окружения
TMPDIR
, а если она не определена, приемлемое значение по умолчанию (обычно
/tmp
). Это хорошее соглашение, которое следует принять на вооружение в своих программах.
• Функция
abort()
посылает вызывающему процессу сигнал
SIGABRT
. Результатом является завершение процесса и создание дампа ядра, предположительно для отладки.
•
setjmp()
и
longjmp()
обеспечивают нелокальный переход. Это мощная возможность, которая должна использоваться с осторожностью.
sigsetjmp()
и
siglongjmp()
сохраняют и восстанавливают маску сигналов процесса, когда программа осуществляет нелокальный переход. Проблемы с нелокальными переходами иногда перевешивают их преимущества, соответственно используйте эти процедуры лишь когда нет лучшего способа структурировать ваше приложение.
• Случайные числа полезны для множества приложений. Большинство программ используют псевдослучайные числа — последовательности номеров, которые кажутся случайными, но которые могут быть воспроизведены с помощью одного и того же начального значения.
rand()
и
srand()
являются первоначальными функциями API, стандартизованными языком С. На многих системах
rand()
использует низкокачественный алгоритм,
random()
и
srandom()
используют лучший алгоритм, включены в стандарт POSIX и являются предпочтительными по сравнению с
rand()
и
srand()
. Используйте специальные файлы
/dev/random
и
/dev/urandom
, если (а) они доступны и (б) если вам нужны случайные числа высокого качества.
• Три функции API предоставляют все более мощные возможности для развертывания метасимволов (подстановки символов).
•
fnmatch()
является простейшей, возвращающей true/false, если данная строка соответствует или не соответствует шаблону символов подстановки оболочки.
•
glob()
просматривает файловую систему, возвращая список путей, которые соответствуют данному шаблону. Когда требуются стандартные возможности
glob()
, следует использовать эту функцию. Хотя GLIBC версия
glob()
имеет некоторые расширения, переносимые программы, которым нужны дополнительные возможности, должны вместо этого использовать
wordexp()
. (Программы, которые будут работать лишь на системах GNU/Linux, не должны стесняться использовать полную мощь GLIBC
glob()
.)
•
wordexp()
не только делает то, что делает
glob()
, но также выполняет полное развертывание слов в стиле оболочки, включая развертывание тильды, развертывание переменных оболочки и подстановку команд.
• Функции
regcomp()
и
regexec()
обеспечивают доступ к базовым и расширенным регулярным выражениям POSIX. Используя одну из этих функций, можно заставить свою программу вести себя идентично со стандартными утилитами, значительно упрощая использование программы пользователями, знакомыми с GNU/Linux и Unix.
Упражнения
1. Используйте
read()
и
memcmp()
для написания простой версии программы
cmp
, которая сравнивает два файла. Вашей версии не нужно поддерживать какие-нибудь опции.
2. Используйте макрос
<stdio.h> getc()
и прямое сравнение каждого прочитанного символа для написания другой версии
cmp
, которая сравнивает два файла. Сравните производительность этой версии с производительностью написанной в предыдущем упражнении.
3. (Средней трудности) Рассмотрите функции
<stdio.h> fgets()
и GLIBC
getline()
. Полезна ли
memcpy()
для их реализации? Набросайте с ее использованием возможную реализацию
fgets()
.
4. (Трудное) Найдите исходный код GLIBC версии
memcmp()
. Он должен быть на одном из CD-ROM с исходным кодом в вашем дистрибутиве GNU/Linux, или же вы можете найти его в сети. Исследуйте код и объясните его.
5. Проверьте свою память. Как
tmpfile()
организует удаление файла, когда закрыт указатель файла?
6. Используя
mkstemp()
и
fdopen()
, а также другие необходимые функции или системные вызовы, напишите свою версию
tmpfile()
. Протестируйте ее тоже.
7. Опишите преимущества и недостатки использования
unlink()
для имени файла, созданного
mkstemp()
, непосредственно после возвращения
mkstemp()
.
8. Напишите свою версию
mkstemp()
, используя
mktemp()
и
open()
. Как вы можете обеспечить те же гарантии уникальности, которые обеспечивает
mkstemp()
?