Как-то раз я спросила у пользователей Mastodon, что их не устраивает в работе с терминалом, и одним из ярких замечаний оказалось «редактирование уже введённой команды».
Мне эта проблема тоже реально знакома. Несмотря на то, что ввод текста и его редактирование является «базовой» задачей, мне потребовалось около 15 лет каждодневной работы с терминалом, чтобы привыкнуть к использованию
Ctrl+A
для перехода к началу строки (или
Ctrl+E
для перехода в конец — я использовала вместо этого
Home
/
End
).
Так что сегодня речь пойдёт о том, что ввод текста порой вызывает сложности. Я также поделюсь с вами кое-какими советами, которые сама была бы рада услышать давно.
Несогласованность между разными программами
В значительной степени ввод текста в терминале усложняет то, что разные программы обрабатывают его по-разному. Например:
- Некоторые программы (
cat
, nc
, git commit --interactive
и так далее) не поддерживают использование стрелок. Если вы будете нажимать в них соответствующие клавиши, то увидите лишь ^[[D^[[D^[[C^[[C^
.
- Многие программы (вроде
irb
, python3
в Linux и другие) используют библиотеку readline
, которая предоставляет богатую базовую функциональность (просмотр истории, клавиши стрелок и так далее).
- Некоторые программы (например,
/usr/bin/python3
на моём Mac) поддерживают самые простые возможности ввода вроде использования стрелок, но не другие вроде Ctrl+влево
или обратного поиска с помощью Ctrl+R
.
- В некоторых программах (вроде оболочки
fish
, ipython3
, micro
или vim
) реализована собственная продуманная система ввода, специализированная конкретно под них.
Так что вариаций получается множество, и, пожалуй, стоит проговорить каждый пункт подробнее.
Пункт 1: основа
Во-первых, есть «основа» — что происходит, если программа просто получает текст через вызов
fgets()
или другую функцию и больше никак не стремится повысить удобство в работе. Для меня использование подобных инструментов обычно выглядит так — если я запускаю установленную на моей машине версию
dash
(довольно минималистичную оболочку) и нажимаю стрелку влево, то она просто выводит в терминал
^[[D
.
$ ls l-^[[D^[[D^[[D
Поначалу не кажется, что все эти инструменты «базового» уровня имеют много общего, но по факту есть несколько функциональных особенностей, которые вы получаете автоматически просто от самого терминала без какой-либо помощи со стороны программы.
Что же это за возможности:
- Естественно, ввод текста.
- Обратное перемещение курсора.
Ctrl+W
для удаления предыдущего слова.
Ctrl+U
для удаления всей строки.
- Ещё несколько возможностей, не связанных с редактированием текста (например,
Ctrl+C
для прерывания процесса, Ctrl+Z
для его приостановки и так далее).
Такие возможности нельзя назвать крутыми, но их наличие означает, что если вы хотите удалить слово, то обычно можете сделать это с помощью
Ctrl+W
вместо того, чтобы 15 раз нажимать возврат, даже если работаете в среде, которая не предлагает никакой функциональности. Список всех поддерживаемых вашим терминалом комбинаций с клавишей
Ctrl
можно вывести командой
stty -a
.
Пункт 2: инструменты, которые используют readline
Следующей группой идут инструменты, использующие
readline
. Readline — это широко используемая библиотека GNU, которая позволяет сделать текст более опрятным. Вот мои любимые комбинации, которые предоставляет эта библиотека:
Ctrl+E
(или End
) для перехода в конец строки.
Ctrl+A
(или Home
) для перехода в начало строки.
Ctrl+влево
/вправо
для перемещения вперёд/назад на 1 слово.
Стрелка вверх
для возврата к предыдущей команде.
Ctrl+R
для поиска по истории.
При этом вы также можете использовать
Ctrl+W
/
Ctrl+U
из «базового» списка, хотя
Ctrl+U
вместо удаления всей строки удаляет только текст от курсора и до начала строки. Думаю, что
Ctrl+W
также может несколько иначе трактовать понятие «слова».
Есть и многие другие комбинации (вот полный список). Я же перечислила только те, которые часто использую сама.
Наиболее известным инструментом, использующим
readline
, наверняка является оболочка
bash
(когда вы используете
Ctrl+R
для поиска по истории в
bash
, то эту возможность по факту предоставляет
readline
), но есть и много других программ — например,
psql
,
irb
,
python3
и так далее.
▍ Совет: можно использовать readline из любого инструмента с помощью rlwrap
Одним из самых приятных моментов я нахожу то, что если у вас есть программа вроде
nc
без поддержки
readline
, то вы можете просто выполнить
rlwrap nc
, чтобы эту поддержку в неё встроить.
Это невероятная возможность, которая делает многие почти непригодные для использования инструменты более удобными в работе. Можно даже включить в
rlwrap
собственные варианты автозавершения, хотя я никогда этого не пробовала.
Почему инструменты могут не использовать readline
Думаю, что поддержка
readline
может отсутствовать в инструментах по следующим причинам:
- Программа очень проста (например,
cat
или nc
) и мейнтейнеры, возможно, не хотят привносить в неё относительно крупную зависимость.
- Нюансы лицензирования. Если лицензия программы не GPL-совместима —
readline
имеет лицензию GPL, а не LGPL.
- Интерактивной является лишь небольшая часть программы, в связи с чем поддержку
readline
могли не счесть как значимый элемент. Например, в git
немного интерактивных функций (таких как git add -p
), и обычно вы просто вводите один символ вроде y
или n
— если же требуется ввести что-то более значительное, git
переносит вас в текстовый редактор.
Например, в
idris2
говорят, что не задействуют
readline
ради сокращения числа зависимостей и для получения более интерактивных возможностей предлагают использовать
rlwrap
.
Как понять, используете ли вы readline
Простейший тест, какой мне приходит на ум, это нажатие
Ctrl+R
. Если вы увидите:
(reverse-i-search)`':
Значит, наверняка используете
readline
. Естественно, это не 100%-метод (некоторые иные библиотеки тоже могут использовать термин
reverse-i-search
), но я не знаю другую систему, которая бы задействовала его для поиска по истории.
Комбинации клавиш readline взяты из Emacs
Поскольку я пользуюсь
vim
, то далеко не сразу поняла, откуда взяты эти комбинации (почему
Ctrl+A
используется для перехода в начало строки??? Очень странно).
Как понимаю я, эти привязки были позаимствованы из Emacs —
Ctrl+A
и
Ctrl+E
делают в Emacs то же, что и в Readline. Так что предполагаю, что и многие другие комбинации между ними тоже совпадут, хотя я пробовала
Ctrl+W
и
Ctrl+U
в Emacs, и в нём их действия отличаются от действий в терминале. В общем, отличия всё же есть.
Подробнее об истории проекта Readline можно почитать
здесь.
Пункт 3: другая библиотека ввода (вроде libedit)
На моём ноутбуке с Mac
/usr/bin/python3
работает странным половинчатым образом, поддерживая лишь часть возможностей
readline
(например, клавиши стрелок). Скажем, при нажатии
Ctrl+влево
программа выводит
;5D
:
$ python3
>>> importt subprocess;5D
Разобраться с этим вопросом мне помогли ребята с Mastodon. Оказывается, в предустановленном на Mac дистрибутиве Python модуль
readline
по факту заменён модулем
libedit
, который представляет аналогичную библиотеку, но с менее широкой функциональностью. Причина может заключаться в том, что Readline имеет
лицензию GPL.
В конечном итоге выяснить, что в моей версии Python используется
libedit
, я смогла так:
$ python3 -c "import readline; print(readline.__doc__)"
Importing this module enables command line editing using libedit readline.
Тем не менее обычно Python использует именно
readline
, если устанавливается под Linux или через Homebrew. Просто конкретная версия, которую инженеры Apple включают в свои системы, работает на
libedit
.
Кроме того, в Python 3.13
собираются убрать зависимость от
readline
, заменив её кастомной библиотекой, так что вскоре выражение «Python использует readline» перестанет быть актуальным.
Предполагаю, что на Mac есть и другие программы, которые используют
libedit
, но я в этом не разбиралась.
Пункт 4: кастомное решение
К последней группе программ относятся те, в которых есть собственная (а иногда и намного более изощрённая) система редактирования текста. К ним относятся:
- Большинство редакторов текста для терминала (
nano
, micro
, vim
, emacs
и так далее).
- Некоторые оболочки вроде
fish
. Например, fish
позволяет при вводе команды использовать отмену через нажатие Ctrl+Z
. В zsh
задействуется текстовый редактор zle
.
- Некоторые REPL вроде
ipython
, в котором вместо readline
используется библиотека prompt_toolkit
.
- Многие другие программы (вроде
atuin
).
Вот некоторые из их особенностей:
- Более эффективное автозавершение, подстроенное под сам инструмент.
- Более удобное управление историей (например, с выделением синтаксиса) в сравнении с тем, которое по умолчанию предоставляет
readline
.
- Больше всевозможных комбинаций клавиш.
▍ Кастомные системы ввода зачастую основаны на readline
Я решила посмотреть, как обрабатывает ввод
Atuin (прекрасный инструмент для поиска по истории оболочки, которым я начала пользоваться недавно). Если взглянуть на
код и его обсуждение, то становится ясно, что хоть реализация этого инструмента и кастомная, основана она именно на
readline
. На мой взгляд, это разумно, так как многие пользователи привыкли к используемым в ней комбинациям клавиш, и это обеспечивает для них дополнительное удобство при работе.
Аналогично дела обстоят с
prompt_toolkit
(библиотекой, которую использует IPython) — фактически она поддерживает множество опций (включая привязки клавиш в стиле
vi
), но по умолчанию в ней используются привязки именно как в
readline
.
И есть немало программ, которые поддерживают самые простые привязки клавиш
vim
(вроде
j
для «вниз» и
k
для «вверх»). Например, Fastmail поддерживает
j
и
k
, несмотря на то, что основная часть остальных его привязок не имеют отношения к
vim
.
Предполагаю, что большинство кастомных систем ввода на основе
readline
имеют различные тонкие расхождения с этой библиотекой, но меня это не волнует, поскольку я крайне плохо разбираюсь в большинстве возможностей
readline
. Я использую всего где-то 5 комбинаций, поэтому до тех пор, пока такие системы поддерживают 5 базовых известных мне команд (которые в них есть всегда), меня это вполне устраивает. Причём эти кастомные системы зачастую предоставляют намного более качественное автозавершение, чем можно получить при использовании только
readline
, поэтому обычно я предпочитаю именно их.
Многие оболочки поддерживают комбинации клавиш из редактора vi
Bash
,
zsh
и
fish
предлагают для ввода текста «режим vi». В очень
ненаучном опросе, который я провела на Mastodon, 12% людей сказали, что используют именно его. Так что, похоже, этот режим довольно популярен.
В
readline
тоже есть «режим vi» (таким образом реализована её поддержка в Bash), то есть по аналогии эта поддержка есть и во многих других программах.
Я всегда считала, что режим
vi
очень крут, но хоть я и пользуюсь
vim
, почему-то его так и не освоила.
Важно понимать ситуацию
Я долгие годы недоумевала, почему используемое мной приложение командной строки не работает так, как я бы хотела. Поэтому хорошо, когда можешь в той или иной степени понять, с чем имеешь дело.
Думаю, что при вводе текста в командную строку я размышляю примерно так:
- Работают ли клавиши стрелок? Возможно, системы ввода нет совсем, но я по крайней мере могу использовать
Ctrl+W
и Ctrl+U
, а также дополнить инструмент с помощью rlwrap
, если мне потребуется больше возможностей.
- Будет ли
Ctrl+R
выводить reverse-i-search
? Если да, то это наверняка readline
, и тогда я смогу использовать все привычные мне комбинации, а также выводить какую-то базовую историю и получать предыдущую команду нажатием клавиши вверх
.
- Делает ли
Ctrl+R
что-то другое? В этом случае, скорее всего, используется кастомная библиотека, которая будет работать более-менее схожим с readline
образом. При этом, если я захочу узнать, как конкретно она работает, то всегда могу заглянуть в документацию.
Возможность подобным образом проверить, что конкретно происходит при использовании разных комбинаций, делает командную строку более предсказуемой и менее хаотичной.
О чём в этом посте не говорилось
При вводе текста существует и много других сложностей, о которых я не сказала. Например:
- проблемы, связанные с
ssh
/ tmux
/ и прочим,
- переменная среды
TERM
,
- то, что разные терминалы (
gnome
, iTerm
, xterm
и прочие) по-разному реализуют копирование/вставку текста,
- Юникод,
- и другие.
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻