Глава 35. Соответствие шаблону

Постановка задачи
Идеи реализации
Неспортивное решение
Рекурсивное решение
Разработка
Неспортивное решение
Рекурсивное решение
Готовая программа
Неспортивное решение
Рекурсивное решение

В командном языке операционной системы Linux имеется одна полезная возможность. Если требуется выполнить некоторую команду сразу для нескольких файлов (скажем, показать информацию об этих файлах или удалить их), можно перечислить имена файлов в командной строке. Если же имена файлов однотипны, можно вместо перечня имён задать шаблон, к которому подходят эти имена.

Например, для удаления всех файлов в текущей директории, имена которых оканчиваются на .mp3, запускаем команду

Для вывода информации о файлах в директории examples/perl, чьи имена начинаются с fibonacci- и оканчиваются на .pl, годится команда

Для описания всех файлов в форматах Open Document (их имена оканчиваются на .odt, .ods, .odp, .odg, .odb и .odf) подойдёт шаблон *.od[tspgbf]. Если требуется подставить в командную строку имена файлов, состоящие ровно из четырёх символов, используем шаблон ????.

Всё это очень напоминает регулярные выражения, которые мы обсудили в главе 30. «Регулярные выражения». Действительно, мы имеем дело с упрощённым диалектом языка регулярных выражений. В шаблонах командной строки звёздочка * означает «любое количество символов» и соответствует комбинации .* в языке регулярных выражений Perl. Вопросительный знак в шаблонах по смыслу совпадает с . в регулярных выражениях: он обозначает любой символ. Обозначение для символьного класса, состоящего из перечисленных символов, точно такое же, как и в регулярных выражениях: [abc] означает какой-то из символов a, b, c.

Следует заметить, что шаблоны командной строки считаются привязанными к началу и к концу имени файла.

Поясним, что происходит, когда в командной строке встречаются шаблоны. Ещё до запуска команды командный интерпретатор, обнаружив шаблон, отыскивает все файлы с именами, подходящие под него. Список найденных имён подставляется затем вместо слова с шаблоном (имена файлов в списке разделяются пробелами). Например, если среди файлов текущей директории имеются три в формате Open Document, Text.odt, Spreadsheet.ods и Presentation.odp, команда

% ls -l *.od[tspgbf]

как будто преобразуется в команду

% ls -l Text.odt Spreadsheet.ods Presentation.odp

И только в том случае, если файлов с подходящими именами не находится, шаблон остаётся в командной строке как есть.

Для поиска файлов, чьи имена соответствуют подобным шаблонам, в Perl имеется встроенная процедура glob. К примеру, команда

Perl
my @audioFiles=glob('*.mp3 *.wav *.ogg *.ac3 *.mka *.au *.flac');

отправит в массив @audioFiles имена всех аудиофайлов, найденных в текущей директории.

[Примечание]Примечание

В старинной операционной системе DOS тоже поддерживались шаблоны имён файлов. Метасимволы ? и * имели тот же смысл, что и в Linux. Разница состоит в том, что обработка шаблонов возлагалась не на командный интерпретатор, а на сами программы. На наш взгляд, это было не очень разумно, поскольку каждая программа, работающая с файлами, должна была самостоятельно реализовывать обработку шаблонов.

Наша задача — написать программу matches.pl, которая принимает в командной строке два параметра: шаблон и строку. Программа выводит Да, если строка подходит под шаблон, и Нет в противном случае:

% ./matches.pl 't*e' 'template' Да % ./matches.pl 't?mplat?' 'template' Да % ./matches.pl 't??' 'template' Нет

Обратите внимание, что символы *, ?, [ и ] являются метасимволами в командном языке. Если шаблон, содержащий эти символы, не заключить в кавычки, произойдёт нежелательная подстановка вместо шаблона списка подходящих имён файлов. Другой, менее удобный способ защитить метасимволы — поместить перед каждым из них бэкслэш \. Кавычки вокруг второго параметра в приведённых примерах не обязательны, поскольку там нет метасимволов. Естественно, сам символ бэкслэш, если нужен как таковой, тоже нуждается в защите. То же самое относится и ко многим другим символам, имеющим особый смысл в командной строке.

Информатика-54© А. Н. Швец