Пред. Начало След.
Наверх
Сведения о документе

Удобства 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)»), подстрока поиска (окружённая символами ` и ') и последняя из команд в истории, в которой эта подстрока присутствует:


[methody@localhost methody]$
 ^R | (reverse-i-search)`':
 i  | (reverse-i-search)`i': ls i
 n  | (reverse-i-search)`in': info
 f  | (reverse-i-search)`inf': info
 o  | (reverse-i-search)`info': info
 ^R | (reverse-i-search)`info': man info
 ^R | (reverse-i-search)`info': info "(bash.info.bz2)Commands For History"

Пример 1. Поиск по истории команд

Пример представляет символы, вводимые пользователем (в левой части до “|”), и содержимое последней строки терминала. Это «кадры» работы с одной и той же строкой, показывающие, как она меняется при наборе. Набрав «info», пользователь продолжил поиск этой подстроки, повторяя Ctrl+R до тех пор, пока не наткнулся на нужную ему команду, содержащую подстроку “info”. Осталось только передать её bash с помощью Enter.

Чтобы история команд могла сохраняться между сеансами работы пользователя, bash записывает её в файл .bash_history, находящийся в домашнем каталоге пользователя. Делается это в момент завершения оболочки: накопленная за время работы история дописывается в конец этого файла. При следующем запуске bash считывает .bash_history целиком. История хранится не вечно, количество запоминаемых команд в .bash_history ограничено (обычно 500 командами, но это можно и перенастроить).

Сокращения

Поиск по истории — удобное средство: длинную командную строку можно не набирать целиком, а выискать и использовать. Однако давнюю команду придётся добывать с помощью нескольких Ctrl+R — а можно и совсем не доискаться, если она уже выбыла оттуда. Для того, чтобы оперативно заменять длинные команды короткими, стоит воспользоваться сокращениями (aliases). В конфигурационных файлах командного интерпретатора пользователя обычно уже определено несколько сокращений, список которых можно посмотреть с помощью команды alias без параметров:


[methody@localhost methody]$ alias
 alias cd..='cd ..'
 alias cp='cp -i'
 alias l='ls -lapt'
 alias ll='ls -laptc'
 alias ls='ls --color=auto'
 alias md='mkdir'
 alias mv='mv -i'
 alias rd='rmdir'
 alias rm='rm -i'

Пример 2. Просмотр заранее определённых сокращений

Выяснилось, что по команде ls вместо утилиты /bin/ls bash запускает собственную команду-сокращение, превращающееся в команду ls --color=auto. Повторно появившуюся в команде подстроку “ls” интерпретатор уже не обрабатывает, во избежание вечного цикла. Например, команда ls -al превращается в результате в ls --color=auto -al. Точно так же любая команда, начинающаяся с rm, превращается в rm -i (interactive), в результате чего ни одно удаление не обходится без вопросов в стиле «rm: удалить обычный файл `файл'?». Избавиться от ненужного сокращения можно с помощью команды unalias.

Достраивание

Сокращения позволяют быстро набирать команды, однако никак не затрагивают имён файлов, которые чаще всего и оказываются параметрами этих команд. Бывает, что набранной строки — пути к файлу и нескольких первых букв его имени — достаточно для однозначного указания на этот файл, потому что по введённому пути болшьше файлов, чьё имя начинается на эти буквы, просто нет. Чтобы не дописывать оставшиеся буквы в bash можно нажать клавишу Tab. И bash сам достроит имя файла до полного (снова воспользуемся методом «кадров»):


[methody@localhost methody]$ ls -al /bin/base
 Tab	| [methody@localhost methody]$ ls -al /bin/basename
-rwxr-xr-x  1 root root 12520 Июн  3 18:29 /bin/basename
[methody@localhost methody]$ base
 Tab	| [methody@localhost methody]$ basename
 Tab	| [methody@localhost methody]$ basename ex
 Tab	| [methody@localhost methody]$ basename examples/
 Tab	| [methody@localhost methody]$ basename examples/sample-file
sample-file

Пример 3. Использование достраивания

Дальше — больше. Оказывается, и имя команды можно вводить не целиком: оболочка догадается достроить набираемое слово именно до команды, раз уж это слово стоит в начале командной строки. Таким образом, команда basename examples/sample-file была набрана за восемь нажатий клавиш («base» и четыре Tab)! Не потребовалось вводить начало имени файла в каталоге examples, потому что файл там был всего один.

Выполняя достраивание (completion), bash может вывести не всю строку, а только ту её часть, относительно которой у него нет сомнений. Если дальнейшее достраиване может пойти несколькими путями, то однократное нажатие Tab приведёт к тому, что bash растерянно пискнет1, а повторное — к выводу под командной строкой списка всех возможных вариантов. В этом случае надо подсказать командной оболочке продолжение: дописать несколько символов, определяющих, по какому пути пойдёт достраивание, и снова нажать Tab.

Дополнения в bash находятся ещё не на самой вершине удобства и экономии нажатий на клавиши. Если в bash несколько типов достраивания (по именам файлов, по именам команд и т. п.), то в zsh их сколько угодно: существует способ запрограммировать любой алгоритм достраивания и задать шаблон командной строки, в которой именно этот способ будет применяться.

Генерация имён файлов

Достраивание очень удобно, когда цель пользователя — задать один конкретный файл в командной строке. Если же нужно работать сразу с несколькими файлами — например для перемещения их в другой каталог с помощью mv, достраивание не помогает. Необходим способ задать одно «общее» имя, которое будет описывать сразу группу файлов, с которыми будет работать команда. В подавляющем большинстве случаев это можно сделать при помощи шаблона.

Шаблоны

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

Использование шаблонов

Шаблоны используются в нескольких конструкциях shell. Главное место их применения — командная строка. Если оболочка видит в командной строке шаблон, она немедленно заменяет его на список файлов, имена которых ему соответствуют. Команда, которая затем вызывается, получает в качестве параметров список файлов уже безо всяких шаблонов, как если бы этот список пользователь ввёл вручную. Эта способность командного интерпретатора называется генерацией имён файлов.


[methody@localhost methody]$ ls .bash*
 .bash_history  .bash_logout  .bash_profile  .bashrc
[methody@localhost methody]$ /bin/e*
 /bin/ed /bin/egrep /bin/ex
[methody@localhost methody]$ ls *a*
 sample-file
[methody@localhost methody]$ ls -dF *[ao]*
 Documents/  examples/  loop  to.sort*

Пример 4. Использование шаблона в командной строке

При использовании шаблонов новичок может натолкнуться на несколько «подводных камней». В приведённом примере только первая команда срабатывает не вопреки ожиданиям: шаблон “.bash*” был превращён командной оболочкой в список файлов, начинающихся на .bash, этот список получила в качестве параметров командной строки утилита ls, после чего честно его вывела. “/bin/e*” — это на самом деле опасная команда, с которой в данном случае просто повезло: этот шаблон превратился в список файлов из каталога /bin, начинающихся на “e”, и первым файлом в списке оказалась безобидная утилита /bin/echo. Поскольку в командной строке ничего, кроме шаблона, не было, именно строка /bin/echo была воспринята оболочкой в качестве команды, которой — в качестве параметров — были переданы остальные элементы списка — /bin/ed, /bin/egrep и /bin/ex.

Что же касается 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.

Если перед любым специальным символом стоит “\”, этот символ лишается специального значения, экранируется: пара “\символ” заменяется командным интерпретатором на “символ” и передаётся в командную строку безо всякой дальнейшей обработки:


[methody@localhost methody]$ echo *o*
 Documents loop to.sort
[methody@localhost methody]$ echo \*o\*
 *o*
[methody@localhost methody]$ echo "*o*"
 *o*
[methody@localhost methody]$ echo *y*
 *y*
[methody@localhost methody]$ ls *y*
 ls: *y*: No such file or directory

Пример 5. Экранирование специальных символов и обработка «пустых» шаблонов

Обратите внимание, что шаблон, которому не соответствует ни одного имени файла, bash раскрывать не стал, как если бы все “*” в нём были экранированы. В самом деле, какое из двух зол меньшее: изменять интерпретацию спецсимволов в зависимости от содержимого каталога, или сохранять логику интерпретации с риском превратить команду с параметрами в команду без параметров? Если бы, допустим, шаблон, которому не нашлось соответствия, попросту удалялся, то команда ls *y* превратилась бы в ls и неожиданно выдала бы содержимое всего каталога. Авторы bash (как и Стивен Борн, автор самой первой командной оболочки — sh) выбрали более непоследовательный, но и более безопасный первый способ3.

Лишить специальные символы их специального значения можно и другим способом. Разделители (пробелы, символы табуляции и символы перевода строки) перестают восприниматься таковыми, если часть командной строки, их содержащую, окружить двойными или одинарными кавычками. В кавычках престаёт «работать» и генерация имён (как это видно из примера), и интерпретация других специальных символов. Двойные кавычки, однако, допускают выполнение подстановок переменной окружения и результата работы команды.


1Все терминалы должны уметь выдавать звуковой сигнал при выводе управляющего символа Ctrl+G. Для этого не нужно запускать никаких дополнительных программ: «настоящие» терминалы имеют встроенный динамик, а виртуальные консоли обычно пользуются системным («пищалкой»). В крайнем случае разрешается привлекать внимание пользователя другими способами: например, эмулятор терминала screen пишет в служебной строке «wuff-wuff» («гав-гав»).

2Генерация имён файлов в zsh предусматривает специальный шаблон “**”, которому соответствуют подстроки с любым количеством “/”. Пользоваться им следует крайне осторожно, понимая, что при генерации имён по такому шаблону выполняется операция, аналогичная не ls, а ls -R или find. Так, использование “/**” в начале шаблона вызовет просмотр всей файловой системы!

3Авторы zsh пошли по другому пути: в этой версии shell использование шаблона, которому не соответствует ни одно имя файла, приводит к ошибке, и соответствующая команда не выполняется.

Пред. Начало След.
Наверх
Сведения о документе