Регулярные выражения

Как известно, все пользователи-POSIX'ивисты должны быть в обязательном порядке привержены одному из семи смертных грехов. И грех этот -- леность, можно сказать, показатель профессиональной пригодности линуксоида.

В соответствие со своей леностью разработчики POSIX-систем придумывают способы, как бы им минимизировать свои усилия. А пользователи из лени изощряются в применении этих приемов на практике. В частности -- в том, как свести к минимуму набор в командной строке.

Собственно говоря, этой цели служили почти все приемы, описанные выше. Осталось осветить немногое. А именно -- регулярные выражения, реализуемые с помощью т.н. специальных символов (или метасимволов).

Элементарная, и весьма частая, в духе школьных, задача: из каталога dir1 требуется скопировать все файлы в каталог dir2. Так неужели все они должны быть перечислены в качестве аргументов команды cp? Нет, нет, и еще раз нет. Ибо для этой цели придуманы шаблоны имен файлов. Самый часто используемый из них -- специальный символ * (вроде бы я о нем уже говорил?). Он подменяет собой любое количество любых символов (в том числе -- и нулевое, то есть отсутствие символов вообще). То есть для решения предложенной задачи нам достаточно дать команду:

$ cp dir1/* dir2

Чуть усложним условия: к копированию из dir1 предназначены не все файлы, а только html-документы, традиционно имеющие расширение html (строго говоря, в POSIX-системах нет расширений в понимании DOS, но об этом мы поговорим в другом месте). Решение от этого не становится сложнее:

$ cp dir1/*html dir2

Обращаем внимание: в Linux, в отличие от DOS/Windows, шаблон * подменяет действительно любые последовательности символов, в том числе и точки в середине имени, то есть необходимости указывать шаблон как *.html, нет.

Однако тут можно вспомнить, что html-документы могут иметь и расширение htm (как известно, в DOS имя файла строится по схеме 8.3). Не пропустим ли мы их таким образом при копировании? Таким -- безусловно, пропустим. Однако нам на помощь придет другой шаблон -- символ ?. А соответствует он любому единичному символу (или -- его отсутствию, т.е. символу null). И значит, если команда из примера будет модифицирована таким образом:

$ cp dir1/*htm? dir2

то она гарантированно охватит все возможные маски html-документов.

Вроде все хорошо. Однако нет: из каталога dir1 нам нужно скопировать только три определенных файла -- file1, file2, file3. Не придется ли каждый из них указывать в командной строке с полным путем (а ведь они могут быть и в глубоко вложенном подкаталоге типа dir1/dir11/dir111)? Все равно не придется, на столь хитрую... постановку задачи у нас есть прием с левой резьбой -- символы группировки аргументов, обозначаемые фигурными скобками. Что на практике выглядит так:

$ cp path/{file1,file2,file3} dir2

И приведет к единоразовому копированию всех трех файлов в каталог dir2. Заметим, что сгруппированные аргументы разделяются запятыми без пробелов. И еще: в оболочке bash группируемые аргументы придется полностью вводить руками. Но вот в zsh на них распространяется возможность автодополнения, да и запятая после каждого имени появляется автоматически (и столь же автоматически исчезает при закрытии фигурной скобки).

Группировка аргументов может быть сколь угодно глубоко вложенной. Так, команда

$ mkdir -p dir1/{dir11/{dir111,dir112},dir12/{dir121,dir122}}

в один заход создаст трехуровневую структуру каталогов внутри текущего -- если только не забыть про опцию -p, которая предписывает создавать промежуточные подкаталоги в случае их отсутствия.

И еще несколько примеров. Регулярное выражение для диапазона -- то есть вида [...], подменяет любой из символов, заключенных в квадратные скобки. Символы эти могут даваться списком без пробелов (например, выражение [12345] соответствует любому символу от 1 до 5) или определяться в диапазоне, крайние значения которого разделяются дефисом без пробелов (эквивалентное первому выражение -- [1-5]). Кроме того, символ ^, предваряющий список или диапазон, означает отрицание: выражение [^abc] подменяет любой символ, исключая символы a, b и c.

Последние примеры регулярных выражений могут показаться надуманными. Однако представим. что в том же каталоге dir1, кроме html-документов, содержатся также файлы изображений в различных форматах -- GIF, JPEG, TIFF и так далее (традиционно имеющие одноименные расширения). И все они должны быть скопированы в каталог dir2, а вот как раз html-файлы нам в данный момент без надобности. No problemas, как говорят у них:

$ cp dir1/*[^html] dir2

И в каталоге dir2 окажется все содержимое каталога dir1, за исключением html-файлов.

. .