Регулярные выражения
Как известно, все пользователи-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-файлов.