Как-то раз я спросила у пользователей 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 ?
Комментарии (30)
jackcrane
11.08.2024 09:42+5+ много за rlwrap
readline настраивается через /etc/inputrc или ~/.inputrc см man 3 readline
sundmoon
11.08.2024 09:42+4К сожалению карма не позволяет поставить люто-бешеный плюс. Сам хейтил линукс вплоть до прошлого десятилетия именно из-за бардака в терминалах.
Возмущала покорность линуксоидов и, ну ладно не могут исправить положение - так хотя бы они объясняли внятно, "кто тут на ком стоял". Лет бы 15, а лучше 20 назад эту статью...slonopotamus
11.08.2024 09:42А что произошло в прошлом десятилетии?
sundmoon
11.08.2024 09:42+2Пройдя через разные стадии принятия неизбежного и расставшись с иллюзорными надеждами на mc, я приучился, стиснув зубы, сходу запускать nano - где хотя бы стрелки и Del с Backspace работали по-людски. Ну и putty выручал. Встречным образом, в линуксах шире разошлись инструменты с readline.
А со временем и вовсе настал кроссплатформенный рай... Не столь давно наткнулся на Zellij - вроде вот оно счастье - но быстро понял, что оно для меня оверкил. И tmux со screen я так и не осилил: лучше запущу столько окон и вкладок Windows Terminal, сколько мне нужно. А линь один из рантаймов, иногда остро необходимый и, наконец-то, очеловечившийся.
saboteur_kiev
11.08.2024 09:42+5cat
,nc
,git commit --interactive
Что-то я тут запутался с первого абзаца.
Какие стрелки в cat, это команда для вывода а не редактированиякакие проблемы со стрелками в git commit, там же гит не причем, вопрос в том какая оболочка и какой редактор по умолчанию, в mingw может быть и msword прикрутить можно =) ?
Проблемы с непечатаемыми символами в терминале, или проблемы передачи хоткеев через различные протоколы и программы (rdp/ssh/и учитывая современные технологии с контейнерами и виртуализацией, еще не всегда понятен трафик ввода-вывода). Они есть, но нужно все-таки уточнять...
unreal_undead2
11.08.2024 09:42+1Какие стрелки в cat, это команда для вывода а не редактирования
С помощью cat >paper.tex теоретически можно статьи писать ) Хотя реально с точки зрения простого пользователя актуальнее ситуация "вывели большой файл, почему стрелками не листается?". То, что реально мы уже не в cat, а в шелле, можно ли вообще получить строки выше - зависит от терминала, а вообще для решения проблемы надо использовать less - это уже какая то чёрная магия )
saboteur_kiev
11.08.2024 09:42+1а less тут причем? Какое отношение пагинатор имеет к редактированию?
unreal_undead2
11.08.2024 09:42+1Решает проблему со стрелками в cat.
saboteur_kiev
11.08.2024 09:42+2cat никак не обрабатывает стрелки. он не редактор.
less их обрабатывает частично, для навигации по тексту. Но он тоже не редактор, курсор он не двигает, только текст.
для решения проблемы редактирования текста, надо его редактировать редактором. Тогда будет уже можно высказывать претензии к протоколу и терминалу, если что-то не работает.
unreal_undead2
11.08.2024 09:42Стрелки нужны не только в редакторе. И попробуйте всё таки посмотреть на проблему с точки зрения простого пользователя (бухгалтера, музыканта, переводчика), а не программиста, который понимает, как оно устроено.
saboteur_kiev
11.08.2024 09:42Так зачем бухгалтеру или музыканту ковыряться в кривом терминале?
Есть удобный пользовательский софт.
И я не программист, программисты, кстати, зачастую в этом не разбираютсяunreal_undead2
11.08.2024 09:42+1Поставил линукс потому что модно-молодёжно, решил разобраться, для какого то действия посоветовали такие то консольные команды...
И я не программист
Ну скорее всего ITшник, а не гуманитарий )
Так то после Примуса, Бейсика на 8битных компьютерах и прочей истории все эти неудобства/особенности современных консолей какие то мелочи, привыкаешь и забываешь.
Tony-Sol
11.08.2024 09:42+1setopt vi
решил для меня все проблемы с Ctrl-A/E и так далее
gpin
11.08.2024 09:42+1Полностью согласен. Но и он не идеален
Возврат в режим редактирования (esc i) делает нередактируемой строку до курсора. Это раздражает - неудобно и из vim такое поведение давно убрали
Не работают home и end клавиши. esc $ и esc 0 это круто, конечно, но можно пожалуйста home и end тоже
Не стирается символ переноса строки. Надо жать esc j J, чтобы убрать пустую строку
А ещё после перехода на helix надо держать в голове 3 разных vi-like системы хоткеев: как в vi (с проблемами выше), как в vim/neovim (без проблем выше), как в helix (select->edit вместо edit->select, мне так удобнее)
может быть есть где-то плагин для zsh, где эти проблемы vi-mode пофиксили и там хоткеи хотя бы как в vim?
Tony-Sol
11.08.2024 09:42+1может быть есть где-то плагин для zsh, где эти проблемы vi-mode пофиксили и там хоткеи хотя бы как в vim?
есть zsh-vi-mode, но я им не пользовался
после перехода на helix
а helix уже адекватный в плане функционала и сообщества? а то раньше плагинов для него днем с огнем не сыщешь
vtb_k
11.08.2024 09:42+1решил для меня все проблемы с Ctrl-A/E и так далее
А были ли проблемы?
autoload -z edit-command-line zle -N edit-command-line bindkey "^h" edit-command-line
Ctrl+h
и любая команда редактируется в любимом редакторе
valvalva
11.08.2024 09:42+1Очень рекомендую:
(echo '"\e[A": history-search-backward'; echo '"\e[B": history-search-forward') >> /etc/inputrc
paintdrip
11.08.2024 09:42+1Использование
readline
и советы по адаптации команд очень полезны, особенно для тех, кто ежедневно работает в командной строке. Радует, что автор предлагает простые и эффективные решения. Возможно, стоит попробовать инструменты вродеrlwrap
для улучшения взаимодействия с терминалом
vviz
11.08.2024 09:42+2Открою Америку - имеется возможность поставить GNU Midnight Commander? Поставьте его и бросте выбирать наиболее кошерный редактор для консоли.
unreal_undead2
11.08.2024 09:42Запасаемся попкорном и смотрим на холивар "консоль против клонов NC"...
siberianlaika
11.08.2024 09:42Так терминалы и прочее основанное на readline по умолчанию используют же раскладку GNU/Emacs. И стрелочки там работают, просто это биндинги Emacs - Ctrl-B (лево), Ctr-F (право) и пр. При этом поддерживается режим Vi через "set -o vi". Статья про то, как не читают документацию.
Dick_from_mountain
Я бы как-то ключи команд стандартизировал. Иногда разработчики создают абсолютную путаницу из ключей, только им понятную. Вот например cmake -B и --build, я их всё время путаю, как-то можно более наглядно ключи создавать?
domix32
Тут та же проблема что и со стилем кода - кому-то Олман, а кому-то КиР подавай. В итоге у одних однобуквенные флаги разных регистров делают разное, а длинных вообще не завезли (и хэлп максимально полезыный а ля
sed [-Ealnru]
), у кого-то однобуквы всегда капсом (ну почти -scp -P1234
ноscp -i id_rsa.pub
vsssh -p1234 -i id_rsa.pub
), а у третьих однобукв примерно совпадает с длинной командой (ripgrep --help
в качестве примера), а у четвертых длинные параметры через одну черточку делаются. Всё просто потому что каждый парсит аргументы каждый раз по-разному.sundmoon
Базар жеж тут православный, а не какой-то б-гомерзкий Собор типа Powershell.
domix32
За консистентность команд ps ничего особо сказать не могу, выглядело в среднем довольно неплохо, не считая того что большинство командлетов выглядт
Like-That
sundmoon
Изначальная мотивация Джефри Сновера (техлида PS, а перед этим автора WMI) - консистентность параметров (среди прочего).
lennylizowzskiy
Небольшая заметка:
В случае утилит на Rust почти все используют один и тот же crate - clap. Так что опыт ввода флагов для утилит на этом языке в 99% случаев будет одинаков.
domix32
Не только Rust едины. У питона например тоже есть стандартный argparse, который можно настраивать всяко.