Удобства shell: экономия движений
Некоторое время поработав в Linux, понабирав команды в командной строке, приходишь к выводу, что в общении с оболочкой не помешают кое-какие удобства. Одно из таких удобств — возможность редактировать вводимую строку с помощью клавиши Backspace (удаление последнего символа), Ctrl+W (удаление слова) и Ctrl+U (удаление всей строки) — предоставляет сам терминал Linux. Эти команды работают для любого построчного ввода в терминале. Если по каким-то причинам в строчку на экране влез мусор, можно нажать Ctrl+R (redraw) — система выведет в новой строке содержимое входного буфера.
Командная оболочка поддерживает некоторые базовые операции по редактированию командной строки, которых можно ожидать для любого текстового ввода. Речь идёт о клавишах Стрелка влево и Стрелка вправо , с помощью которых можно перемещать курсор по командной строке, и клавише Del , удаляющей символ под курсором, а не позади него. Помимо этого перемещаться в командной строке можно не только по одному сиволу вперёд и назад, но и по словам: команды ESCF / ESCB или Alt+F / Alt+B соответственно (от forward и backward), работают также клавиши Home и End , или, что то же самое, Ctrl+A и Ctrl+E .
История командBash располагает весьма мощным механизмом — возможностью работать с историей команд. Все команды, набранные пользователем, bash запоминает и позволяет обращаться к ним впоследствии. Для работы с историей команд используются клавиши со стрелками — вверх и вниз. По стрелке вверх (можно использовать и Ctrl+P , previous), список поданных команд «прокручивается» от последней к первой, а по стрелке вниз ( Ctrl+N , next) — обратно. Соответствующая команда отображается в командной строке как только что набранная, её можно отредактировать и подать оболочке (подгонять курсор к концу строки при этом не обязательно).
Если необходимо добыть из истории какую-то давнюю команду, проще не гонять список истории стрелками, а поискать в ней с помощью команды Ctrl+R (reverse search). При этом выводится подсказка специального вида («(reverse-i-search)»), подстрока поиска (окружённая символами ` и ' ) и последняя из команд в истории, в которой эта подстрока присутствует:
Чтобы история команд могла сохраняться между сеансами работы пользователя, bash записывает её в файл .bash_history , находящийся в домашнем каталоге пользователя. Делается это в момент завершения оболочки: накопленная за время работы история дописывается в конец этого файла. При следующем запуске bash считывает .bash_history целиком. История хранится не вечно, количество запоминаемых команд в .bash_history ограничено (обычно 500 командами, но это можно и перенастроить).
СокращенияПоиск по истории — удобное средство: длинную командную строку можно не набирать целиком, а выискать и использовать. Однако давнюю команду придётся добывать с помощью нескольких Ctrl+R — а можно и совсем не доискаться, если она уже выбыла оттуда. Для того, чтобы оперативно заменять длинные команды короткими, стоит воспользоваться сокращениями (aliases). В конфигурационных файлах командного интерпретатора пользователя обычно уже определено несколько сокращений, список которых можно посмотреть с помощью команды alias без параметров:
ДостраиваниеСокращения позволяют быстро набирать команды, однако никак не затрагивают имён файлов, которые чаще всего и оказываются параметрами этих команд. Бывает, что набранной строки — пути к файлу и нескольких первых букв его имени — достаточно для однозначного указания на этот файл, потому что по введённому пути болшьше файлов, чьё имя начинается на эти буквы, просто нет. Чтобы не дописывать оставшиеся буквы в bash можно нажать клавишу Tab . И bash сам достроит имя файла до полного (снова воспользуемся методом «кадров»):
Выполняя достраивание (completion), bash может вывести не всю строку, а только ту её часть, относительно которой у него нет сомнений. Если дальнейшее достраиване может пойти несколькими путями, то однократное нажатие Tab приведёт к тому, что bash растерянно пискнет 1 , а повторное — к выводу под командной строкой списка всех возможных вариантов. В этом случае надо подсказать командной оболочке продолжение: дописать несколько символов, определяющих, по какому пути пойдёт достраивание, и снова нажать Tab .
Дополнения в bash находятся ещё не на самой вершине удобства и экономии нажатий на клавиши. Если в bash несколько типов достраивания (по именам файлов, по именам команд и т. п.), то в zsh их сколько угодно: существует способ запрограммировать любой алгоритм достраивания и задать шаблон командной строки, в которой именно этот способ будет применяться.
Генерация имён файлов
Достраивание очень удобно, когда цель пользователя — задать один конкретный файл в командной строке. Если же нужно работать сразу с несколькими файлами — например для перемещения их в другой каталог с помощью mv , достраивание не помогает. Необходим способ задать одно «общее» имя, которое будет описывать сразу группу файлов, с которыми будет работать команда. В подавляющем большинстве случаев это можно сделать при помощи шаблона.
Шаблоны- Шаблону, стостоящему только из обычных символов, соответствует единственная строка, состоящая из тех же символов в том же порядке. Например, шаблону “ abc ” соответствует строка abc , но не aBc или ABC , потому что большие и маленькие буквы различаются.
- Шаблону, состоящему из единственного спецсимвола “ * ”, соответствует любая строка любой длины (в том числе и пустая).
- Шаблону, состоящему из единственного спецсимвола “ ? ”, соответствует любая строка длиной в один символ, например, a , + или @ , но не ab или 8888 .
- Шаблону, состоящему из любых символов, заключённых в квадратные скобки “ [ ” и “ ] ” соответствует строка длиной в один символ, причём этот символ должен встречаться среди заключённых в скобки. Например, шаблону “ [bar] ” соответствуют только строки a , b и r , но не c , B , bar или ab . Символы внутри скобок можно не перечислять полностью, а задавать диапазон, в начале которого стоит символ с наименьшим ASCII-кодом, затем следует “ - ”, а затем — символ с наибольшим ASCII-кодом. Например, шаблону “ [0-9a-fA-F] ” соответствует одна шестнадцатеричная цифра (скажем, 5 , e или C ). Если после “ [ ” в шаблоне следует “ ! ”, то ему соответствует строка из одного символа не перечисленного между скобками.
- Шаблону, состоящему из нескольких частей, соответствует строка, которую можно разбить на столько же подстрок (возможно, пустых), причём первая подстрока будет отвечать первой части шаблона, вторая — второй части и т. д. Например, шаблону “ a*b?c ” будут соответствовать строки ab@c (“ * ” соответвтует пустая подстрока), a+b=c и aaabbc , но не соответствовать abc (“ ? ” соответвтует подстрока c , а для “ c ” соответствия не находится), @ab@c (нет соответствия для “ a ”) или aaabbbc (из трёх b превое соответствует “ b ”, второе — “ ? ”, а вот третье приходится на “ c ”).
Шаблоны используются в нескольких конструкциях shell. Главное место их применения — командная строка. Если оболочка видит в командной строке шаблон, она немедленно заменяет его на список файлов, имена которых ему соответствуют. Команда, которая затем вызывается, получает в качестве параметров список файлов уже безо всяких шаблонов, как если бы этот список пользователь ввёл вручную. Эта способность командного интерпретатора называется генерацией имён файлов.
Что же касается ls *a* , то кажется, что эта команда должна была выдать список файлов в текущем каталоге, имя которых содержит “ a ”. Вместо этого на экран вывелось имя файла из подкаталога examples . Впрочем, никакой чёрной магии тут нет. Во-первых, имена файлов вида “ .bash* ” хотя и содержат “ a ”, но начинаются на точку, и, стало быть, считаются скрытыми. Скрытые файлы попадают в результат генерации имён только если точка в начале указана явно (как в первой команде примера). Поэтому по шаблону “ *a* ” в домашнем каталоге bash нашёл только подкаталог с именем examples , его-то он и передал в качестве параметра утилите ls . Что вывелось на экран в результате образовавшейся команды ls examples ? Конечно, содержимое каталога. Шаблон в последней команде из примера, “ *[ao]* ”, был превращён в список файлов, чьи имена содержат “ a ” или “ o ” — Documents examples loop to.sort , а ключ “ -d ” потребовал у ls показывать информацию о каталогах, а не об их содержимом. В соответствии с ключом “ -F ”, ls расставил “ / ” после каталогов и “ * ” после исполняемых файлов.
Ещё одно отличие генерации имён от стандартной обработки шаблона — в том, что символ “ / ”, разделяющий элементы пути, никогда не ставится в соответствие “ * ” или диапазону. Происходит это не потому, что искажён алгоритм, а потому, что при генерации имён шаблон применяется именно к элементу пути, внутри которого уже нет “ / ”. Например, получить список файлов, которые находятся в каталогах /usr/bin и /usr/sbin и содержат подстроку “ ppp ” в имени, можно с помощью шаблона “ /usr/*bin/*ppp* ”. Однако одного шаблона, который бы включал в этот список ещё и каталоги /bin и /sbin — то есть подкаталоги другого уровня вложенности — по стандартным правилам сделать нельзя 2 .
Если перед любым специальным символом стоит “ \ ”, этот символ лишается специального значения, экранируется: пара “ \символ ” заменяется командным интерпретатором на “ символ ” и передаётся в командную строку безо всякой дальнейшей обработки:
Лишить специальные символы их специального значения можно и другим способом. Разделители (пробелы, символы табуляции и символы перевода строки) перестают восприниматься таковыми, если часть командной строки, их содержащую, окружить двойными или одинарными кавычками. В кавычках престаёт «работать» и генерация имён (как это видно из примера), и интерпретация других специальных символов. Двойные кавычки, однако, допускают выполнение подстановок переменной окружения и результата работы команды.
1Все терминалы должны уметь выдавать звуковой сигнал при выводе управляющего символа Ctrl+G . Для этого не нужно запускать никаких дополнительных программ: «настоящие» терминалы имеют встроенный динамик, а виртуальные консоли обычно пользуются системным («пищалкой»). В крайнем случае разрешается привлекать внимание пользователя другими способами: например, эмулятор терминала screen пишет в служебной строке «wuff-wuff» («гав-гав»).
2Генерация имён файлов в zsh предусматривает специальный шаблон “ ** ”, которому соответствуют подстроки с любым количеством “ / ”. Пользоваться им следует крайне осторожно, понимая, что при генерации имён по такому шаблону выполняется операция, аналогичная не ls , а ls -R или find . Так, использование “ /** ” в начале шаблона вызовет просмотр всей файловой системы!
3Авторы zsh пошли по другому пути: в этой версии shell использование шаблона, которому не соответствует ни одно имя файла, приводит к ошибке, и соответствующая команда не выполняется.