%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82%20%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE%20%D0%BF%D1%80%D0%B8%20%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B8%20%D1%81%D0%BE%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%3F.png)
Когда у меня неотвечающее SSH-соединение, я могу убить его с помощью <enter>~.
. Однако, когда соединение отвечает, ~
выход не работает. Он просто печатает тильду в консоли.
Итак, если я захочу изменить переадресацию портов SSH и нажму <enter>~C<enter>
, все, что я получу, это:
~C: command not found
(Из bash
, а не из ssh
.)
Что мне нужно сделать, чтобы клавиша выхода SSH работала правильно?
РЕДАКТИРОВАТЬ:Я нашел большую зацепку: удаленная оболочка на самом деле была ash
, а не bash
. Когда я запускаю bash
на удаленной машине, клавиша SSH escape работает! Когда я запускаю ash
внутри , bash
снова ash
, она не работает!
Но это очень странно. Клавиша escape должна быть перехвачена SSH-клиентом и даже не перенаправлена в удаленную оболочку. Так почему же должно быть важно, какая именно удаленная оболочка получает входные данные от SSH?
решение1
Простой обходной путь: выполните cat
команду, а затем введите escape-последовательность.
Команда cat
по умолчанию выведет то, что передано stdin
, поэтому во время ее выполнения не будет отправлено никаких экранирующих символов, и вы можете использовать клавишу ssh escape как обычно. После этого просто ctrl-c
вернитесь cat
в оболочку.
Пример
При необходимости откройте командную строку и выполните команду, cat
введя ее cat
и нажав Enter.
$
$ cat
Теперь введите ~?
~?
Supported escape sequences:
~. - terminate connection (and any multiplexed sessions)
~B - send a BREAK to the remote system
~C - open a command line
~R - request rekey
~V/v - decrease/increase verbosity (LogLevel)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
Работает! Теперь просто введите любую команду. Затем, чтобы вернуться к подсказке, нажмите control-C.
^C
$
решение2
Я разгадал секрет!
Как я уже писал в «редактировании» выше, удаленная оболочка была BusyBox ash
, а не bash
.
Из libbb/lineedit.c:2336-2338
источников BusyBox:
/* Print out the command prompt, optionally ask where cursor is */
parse_and_put_prompt(prompt);
ask_terminal();
Это используется для печати командной строки в ash
. Но обратите внимание, как только она печатает приглашение, вызывается другая функция ask_terminal
. Что она ask_terminal
делает? Она печатает следующие символы: <ESCAPE>[6n
.
Вы никогда не увидите эти символы в своем терминале. На самом деле, это управляющий код ANSI терминала. <ESC>[6n
— это команда «Запросить позицию курсора» — она сообщает эмулятору терминала о необходимости отправить обратно другой управляющий код ANSI, который сообщает оболочке, где в окне терминала находится курсор (точка вставки текста).
Итак, как только вы нажимаете Enter
, ash
печатает <ESC>[6n
, и sshd
передает это обратно ssh
в эмулятор терминала и оттуда в него. Сразу же, до того, как вы сможете нажать ~
, ваш эмулятор терминала отправляет что-то вроде <ESC>[47;13R
на стандартный ввод и ssh
передает это по соединению в sshd
и оттуда в ash
, сообщая, ash
где находится ваш курсор.
Теперь клиент SSH на самом деле не знает, что означают эти управляющие коды ANSI. Для SSH они все просто символы, считанные со стандартного ввода. Вместо того, чтобы видеть <ENTER>~C
, клиент SSH видит <ENTER><ESC>[47;13R~C
, и поскольку он не видит ~
сразу после Enter
, он не думает, что это управляющий код.
Вопрос в том, что с этим делать. Было бы неплохо, если бы OpenSSH понимал эти экранированные последовательности ANSI, отправленные терминалом, и по-прежнему принимал бы ~
символ экранирования после команды управления терминалом ANSI. Я могу отправить ребятам из OpenSSH патч и посмотреть, заинтересованы ли они в исправлении этого...
решение3
Вы спрашивалиНеужели клавиша выхода SSH-клиента не должна работать таким образом?
Да, это должно работать так:
Если вы нажмете Enterтогда и на подсказке ~не появится символ, то действие Escape будет выполнено в .~
ssh
Если вы нажмете еще раз, ~он появится в командной строке и будет действовать в рабочей оболочке (bash в вашем примере), которая попытаетсярасширятьи использовать по своему усмотрению.
Обратите внимание, что для работы ~
необходимо быть первым из вашихбуфер строки, поэтому если вы введете любой символ и после этого сотрете всю строку, то ее больше не будетновыйи вам нужно нажать Enterеще раз.
Когда я нажимаю, ~?
я получаю
Поддерживаемые escape-последовательности:
~. - завершить соединение (и любые мультиплексные сеансы)
~B - отправить BREAK на удаленную систему
~C - открыть командную строку
~R - запросить повторный ввод (только протокол SSH 2)
~^Z - приостановить ssh
~# - вывести список перенаправленных соединений
~& - фоновый ssh (при ожидании завершения соединений)
~? - это сообщение
~~ - отправить escape-символ, введя его дважды
(обратите внимание, что escape-символы распознаются только сразу после новой строки.)