Уже некоторое время поработав в Linux, понабирав команды в командной строке, Мефодий пришёл к выводу, что в общении с оболочкой не помешают кое-какие удобства. Одно из таких удобств — возможность редактировать вводимую строку с помощью клавиши Backspace
(удаление последнего символа), «^W
» (удаление слова) и «^U
» (удаление всей строки) — предоставляет сам терминал Linux. Эти команды работают для любого построчного ввода: например, если запустить программу cat
без параметров, чтобы та немедленно отображала вводимые с терминала строки. Если по каким-то причинам в строчку на экране влез мусор, можно нажать «^R
» (redraw) — система выведет в новой строке содержимое входного буфера.
Мефодий не забыл, что cat без параметров следует завершать командой «^D
» (конец ввода). Эту команду, как и предыдущие, интерпретирует при вводе с терминала система. Система же превращает некоторые другие управляющие символы (например, «^C
» или «^Z
») в сигналы. В действительности все управляющие символы, интерпретируемые системой, можно перенастроить с помощью команды stty
. Полный список того, что можно настраивать, выдаёт команда stty -a
:
[methody@localhost methody]$ stty -a
localhost 38400 baud; rows 30; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke
Пример 1. Настройки терминальной линии
При виде столь обширных возможностей Мефодий немедленно взялся читать руководство (man stty
), однако нашёл в нём не так уж много для себя полезного. Из управляющих символов (строки со второй по четвёртую) интересны «^S
» и «^Q
», с помощью которых можно, соответственно, приостановить и возобновить выдачу на терминал (если текста вывелось уже много, а прочесть его не успеваешь). Можно заметить, что настройка erase
(удаление одного символа) соответствует управляющему символу, который возвращается клавишей Backspace
именно виртуальной консоли Linux — «^?
». На многих терминалах клавиша Backspace
возвращает другой символ — «^H
». Если необходимо переопределить настройку erase
, можно воспользоваться командой «stty erase ^H
», причём «^H
» (для удобства) разрешено вводить и как два символа: «^
» и «H
».
Наконец, чтобы лишить передаваемый символ его управляющих функций (если, например, требуется передать программе на ввод символ с кодом 3
, т. е. «^C
»), непосредственно перед вводом этого символа нужно подать команду «^V
» (lnext
):
[methody@localhost methody]$ cat | hexdump -C
Сейчас нажмём Ctrl+C
[methody@localhost methody]$ cat | hexdump -C
Теперь Ctrl+V, Ctrl+C, enter и Ctrl+D^C
00000000 f4 c5 d0 c5 d2 d8 20 43 74 72 6c 2b 56 2c 20 43 |Теперь Ctrl+V, C|
00000010 74 72 6c 2b 43 2c 20 45 6e 74 65 72 20 c9 20 43 |trl+C, enter и C|
00000020 74 72 6c 2b 44 03 0a |trl+D..|
00000027
Пример 2. Экранирование управляющих символов
Здесь Мефодий прервал, как и собирался, работу первого из cat
. При этом до hexdump
, фильтра, переводящего входной поток в шестнадцатеричное предстваление, дело даже не дошло, потому что cat
не успел обработать ни одной строки. Во втором случае «^C
» после «^V
» потеряло управляющий смысл и отобразилось при вводе. С ключом «-C
» hexdump
выводит также и текстовое предстваление входного потока, заменяя непечатные символы точками. Так на точки были заменены и «^C
» (ASCII-код 03
), и возвращаемый Enter
символ конца строки (ASCII-код 0a
, в десятичном виде — 12
). Ни «^V
», ни «^D
» на вход hexdump
, конечно, не попали: их, как управляющие, обработала система.
Прочие настройки stty
относятся к обработке текста при выводе на терминал и вводе с него. Они интересны только в том смысле, что при их изменении работать с комндной оболочкой становится неудобно. Например, настройка echo
определяет, будет ли система отображать на экране всё, что вводит пользователь. При включённом echo нажатие любой алфавитно-цифровой клавиши (ввод символа) приводит к тому, что система (устройство типа tty
) выведет этот символ на терминал. Настройка отключается, когда с клавиатуры вводится пароль. При этом трудно отделаться от ощущения, что ввода с клавиатуры не происходит. Ещё хуже обстоит дело с настройками, состоящими из кусков вида «i
», «o
», «cr
» и «nl
». Эти настройки управляют преобразованием при вводе и выводе исторически сложившегося обозначения конца строки двумя символами в один, принятый в Linux. Может случиться так, что клавиша Enter
терминала возвращает как раз неправильный символ конца строки, а преобразование отключено. Тогда вместо Enter
следует использовать «^J
» — символ, на самом деле соответствующий концу строки.
Во всех случаях, когда терминал находится в непонятном состоянии — не реагирует на Enter
, не показывает ввода, не удаляет символов, выводит текст «ступеньками» и т. п., рекомендуется «лечить» настройки терминала с помощью stty sane
— специальной формы stty
, сбрасывающей настройки терминала в некоторе пригодное к работе состояние. Если непонятное состояние терминала возникло однократно, например, после аварийного завершения экранной программы (редактора vim
или оболочки mc
), то можно воспользоваться командой reset
. Она заново настраивает терминал в полном соответствии с системной конфигурацией (указанной в файле /etc/inittab
, см. лекцию Этапы загрузки системы) и terminfo
.
Если терминал ведёт себя странно, последовательность «^J stty sane^J
» может его вылечить!
Редактирование командной строки
Даже не изучая специально возможностей командной оболочки, Мефодий активно использовал некоторые из них, не доступные при вводе текста большинству утилит (в частности, ни cat
, ни hexdump
). Речь идёт о клавишах Стрелка влево
и Стрелка вправо
, с помощью которых можно перемещать курсор по командной строке, и клавише Del
, удаляющей символ под курсором, а не позади него. В лекции Терминал и командная строка он уже убедился, что эти команды работают в bash
, но не работают для cat
. Более того, для простого командного интерпретатора — sh
— они тоже не работают.
Следовательно, возможности редактора командной строки специфичны для разных командных оболочек. Однако самые необходимые команды редактирования поддерживаются во всех разновидностях shell сходным образом. По словам Гуревича «во всех видах Linux обязательно есть bash
, а если ты достаточно опытен, чтобы устанавливать и настраивать пакеты, можешь установить zsh
, у него возможностей больше, чем может понадобиться одному человеку». Поэтому Мефодий занялся изучением документации по bash
, что оказалось делом непростым, ибо в bash.info
он насчитал более восьми с половиной тысяч строк. Даже про редактирование командной строки написано столько, что за один раз прочесть трудно.
Попытка «наскоком» узнать всё про работу в командной строке принесла некоторую пользу. Во-первых, перемещаться в командной строке можно не только по одному символу вперёд и назад, но и по словам: команды ESCF/ESCB
или Alt+F/Alt+B
соответственно (от forward и bckward), работают также клавиши &home&
и &end&
, или, что то же самое, «^A
» и «^E
». А во-вторых, помимо работы с одной командной строкой, существует ещё немало других удобств, о которых и пойдёт речь в этой лекции.
История команд
Двумя другими клавишами со стрелками — вверх и вниз — Мефодий тоже активно пользовался, не подозрвая, что задействует этим весьма мощный механизм bash
— работу с историей команд. Все команды, набранные пользователем, bash
запоминает и позволяет обращаться к ним впоследствии. По стрелке вверх (можно использовать и «^P
», previous), список поданных команд «прокручивается» от последней к первой, а по стрелке вниз («^N
», next) — обратно. Соответствующая команда отображается в командной строке как только что набранная, её можно отредактировать и подать оболочке (подгонять курсор к концу строки при этом не обязательно).
Если необходимо добыть из истории какую-то давнюю команду, проще не гонять список истории стрелками, а поискать в ней с помощью команды «^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"
Пример 3. Поиск по истории команд
Пример представляет символы вводимые Мефодием (в левой части до «|
») и содержимое последней строки терминала. Это «кадры» работы с одной и той же строкой, показывающие, как она меняется при наборе. Набрав «info», Мефодий продолжил поиск этой подстроки, повторяя «^R
» до тех пор, пока не наткнулся на нужную ему команду, содержащую подстроку «info
». Осталось только передать её bash
с помощью Enter
.
Чтобы история команд могла сохраняться между сеансами работы пользователя, bash
записывает её в файл .bash_history
, находящийся в домашнем каталоге пользователя. Делается это в момент завершения оболочки: накопленная за время работы история дописывается в конец этого файла. При следующем запуске bash
считывает .bash_history
целиком. История хранится не вечно, количество запоминаемых команд в .bash_history
ограничено (обычно 500 командами, но это можно и перенастроить).
Сокращения
Поиск по истории — удобное средство: длинную командную строку можно не набирать целиком, а выискать и использовать. Однако давнюю команду придётся добывать с помощью нескольких «^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'
Пример 4. Просмотр заранее определённых сокращений
С сокращениями Мефодий уже сталкивался в лекции Права доступа, где команда ls отказалась работать в согласии с теорией. Выяснилось, что по команде ls
вместо утилиты /bin/ls
bash
запускает собственную команду-сокращение, превращающееся в команду ls --color=auto
. Повторно появившуюся в команде подстроку «ls
» интерпретатор уже не обрабатывает, во избежание вечного цикла. Например, команда ls -al
превращается в результате в ls --color=auto -al
. Точно так же любая команда, начинающаяся с rm
, превращается в rm -i
(interactive), что Мефодия крайне раздражает, потому что ни одно удаление не обходится без вопросов в стиле «rm: удалить обычный файл `файл
'?».
[methody@localhost methody]$ unalias cp rm mv
[methody@localhost methody]$ alias pd=pushd
[methody@localhost methody]$ alias pp=popd
[methody@localhost methody]$ pd /bin
/bin ~
[methody@localhost bin]$ pd /usr/share/doc
/usr/share/doc /bin ~
[methody@localhost doc]$ cd /var/tmp
[methody@localhost tmp]$ dirs
/var/tmp /bin ~
[methody@localhost tmp]$ pp
/bin ~
[methody@localhost bin]$ pp
~
[methody@localhost methody]$ pp
-bash: popd: directory stack empty
Пример 5. Использование сокращений и pushd/popd
От надоедливого «-i
» Мефодий избавился с помощью команды unalias
, а заодно ввёл сокращения для полюбившихся ему команд bash
— pushd
и popd
. Эти команды, подобно cd
, меняют текущий каталог.
Они названы по аналогии с операциями работы со стеком — push
и pop
.
Разница состоит в том, что pushd
все каталоги, которые пользователь делает текущими, запоминает в особом списке (стеке). Команда popd
удаляет последний элемент этого стека, и делает текущим каталогом предпоследний. Обе команды вдобавок выводят содержимое стека каталогов (то же самое делает и команда dirs
). Команда cd
в bash
также работает со стеком каталогов: она заменяет его последний элемент новым.
- команда-сокращение
- Внутренняя команда shell, задаваемая пользователем. Обычно заменяет одну более длинную команду, которая часто используется при работе в командной строке. Сокращения не наследуются с окружением.
Достраивание
Сокращения позволяют быстро набирать команды, однако никак не затрагивают имён файлов, которые чаще всего и оказываются параметрами этих команд. Бывает, что набранной строки — пути к файлу и нескольких первых букв его имени — достаточно для однозначного указания на этот файл, потому что по введённому пути болшьше файлов, чьё имя начинается на эти буквы, просто нет. Чтобы не дописывать оставшиеся буквы (а имена файлов в Linux могут быть весьма длинными), Гуревич посоветовал Мефодию нажать клавишу 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/-filename-with-
-filename-with-
Пример 6. Использование достраивания
Дальше — больше. Оказывается, и имя команды можно вводить не целиком: оболочка догадается достроить набираемое слово именно до команды, раз уж это слово стоит в начале командной строки. Таким образом, команду basename examples/-filename-with-
Мефодий набрал за восемь нажатий на клавиатуру («base
» и четыре Tab
)! Ему не пришлось вводить начало имени файла в каталоге examples
, потому что файл там был всего один.
Выполняя достраивание (completion), bash
может вывести не всю строку, а только ту её часть, относительно которой у него нет сомнений. Если дальнейшее достраиване может пойти несколькими путями, то однократное нажатие Tab
приведёт к тому, что bash
растерянно пискнет, а повторное — к выводу под командной строкой списка всех возможных вариантов.
Все терминалы должны уметь выдавать звуковой сигнал при выводе управляющего символа «^G
». Для этого не нужно запускать никаких дополнительных программ: «настоящие» терминалы имеют встроенный динамик, а виртуальные консоли обычно пользуются системным («пищалкой»). В крайнем случае разрешается привлекать внимание пользователя другими способами: например, эмулятор терминала screen
пишет в служебной строке «wuff-wuff» («гав-гав»).
В этом случае надо подсказать командной оболочке продолжение: дописать несколько символов, определяющих, по какому пути пойдёт достраивание, и снова нажать Tab
. Поиск ключевого слова «completion» по документации bash
выдал так много информации, что Мефодий обратился к Гуревичу за помощью. Однако тот ответил, что не использует bash
, и поэтому не в состоянии объяснять тонкости его нстройки. Если в bash
— несколько типов достраивания (по именам файлов, по именам команд и т. п.), то в zsh
их сколько угодно: существует способ запрограммировать любой алгоритм достраивания и задать шаблон командной строки, в которой именно этот способ будет применяться.