Что CTRL + 4 (и CTRL + \) делает в bash?

22

Я просто случайно обнаружил, что CTRL+ 4 закрывает программы, читающие stdinввод из командной строки.

Вот как это выглядит, когда я набираю CTRL+ 4или CTRL+ / в программах чтенияstdin

$ cat
wefwef
wefwef
^\Quit
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
^\Quit
$

У меня ^\Quitотображается, а затем программа закрывается. В чем разница с использованием ^Cили ^D? Что делает ^\Quit?

Изменить : обнаружил, что CTRL+ \делает то же самое.

wefwefa3
источник

Ответы:

37

Ctrl + 4 отправляет ^ \

Терминалы отправляют символы (или, точнее, байты), а не ключи. При нажатии клавиши, представляющей печатный символ, терминал отправляет этот символ в приложение. Большинство функциональных клавиш кодируются как escape-последовательности: последовательности символов, начинающиеся с символа 27. Некоторые цепочки ключей вида Ctrl+ characterи несколько функциональных клавиш отправляются в качестве управляющих символов - в наборе символов ASCII , который используется всеми современными компьютерами. использовать в качестве основы (Unicode, ISO Latin- nи т. д. все являются надмножествами ASCII), 33 символа являются управляющими символами: символы с номерами от 0 до 31 и 127. Управляющие символы не могут быть напечатаны, но должны оказывать влияние на приложения; например, символ 10, который является Control-J (обычно пишется ^ J), является символом новой строки, поэтому, когда терминал отображает этот символ, он перемещает курсор на следующую строку, а не отображает глиф. Сам символ выхода является управляющим символом ^ [(значение 27).

Недостаточно управляющих символов, чтобы охватить все комбинации клавиш Ctrl+ character. Только буквы и символы @[\]^_?имеют соответствующий управляющий символ. Когда вы нажимаете Ctrl+ 4или Ctrl+ $(что я предполагаю Ctrl+ Shift+ 4), терминал должен выбрать что-то для отправки. В зависимости от терминала и его конфигурации, есть несколько общих возможностей:

  • Терминал игнорирует Ctrlмодификатор и отправляет символ 4или $.
  • Терминал отправляет escape-последовательность, которая кодирует точную клавишу и модификаторы, которые были нажаты.
  • Терминал отправляет какой-то другой управляющий символ.

Многие терминалы отправляют управляющие символы для некоторых клавиш в строке цифр:

  • Ctrl+ 2→ ^ @
  • Ctrl+ 3→ ^ [
  • Ctrl+ 4→ ^ \
  • Ctrl+ 5→ ^]
  • Ctrl+ 6→ ^^
  • Ctrl+ 7→ ^ _
  • Ctrl+ 8→ ^?

Я не знаю, где возникло это соглашение.

Ctrl+ |отправляет тот же символ, потому что это Ctrl+ Shift+, \а терминал отправляет ^ \ независимо от того, была ли нажата клавиша Shift или нет.

^ \ выходит

Сам терминал (точнее, общая поддержка терминала в ядре) интерпретирует несколько управляющих символов специально. Эта интерпретация может быть настроена для отображения различных символов или отключена приложениями, которые хотят обрабатывать символы самостоятельно. Одна хорошо известная такая интерпретация заключается в том, что ^ M, символ, отправляемый Returnключом, отправляет текущую строку приложению, если терминал находится в режиме готового режима , в котором приложения получают строку за строкой.

Несколько символов отправляют сигналы в приложение на переднем плане. ^ C отправляет сигнал прерывания (SIGINT), который обычно говорит приложению прекратить то, что он делает, и прочитать следующую команду пользователя. Неинтерактивные приложения обычно выходят. ^ \ отправляет сигнал выхода (SIGQUIT), который обычно указывает приложению завершиться как можно скорее, не сохраняя ничего; многие приложения не переопределяют поведение по умолчанию, которое заключается в немедленном уничтожении приложения¹. Поэтому, когда вы нажимаете Ctrl+ 4(или все, что отправляет символ ^ \) в catили bc, ни один из которых не отменяет поведение по умолчанию, приложение завершается.

Сам терминал печатает ^\часть сообщения: это визуальное изображение введенного вами символа, и терминал находится в готовом режиме и с включенным эхом (символы отображаются терминалом, как только вы их набираете, в отличие от режим без эха, когда символы отправляются только в приложение, которое может или не может отображать их). Эта Quitчасть исходит от bash: он замечает, что его дочерний процесс умер от сигнала выхода, и это его способ сообщить вам.

Оболочки обрабатывают все распространенные сигналы, поэтому, если вы вводите ^ \ в оболочке, вы не убиваете сеанс, вы просто получаете новое приглашение, такое же как ^ C.

Вы можете играть с настройками терминала с помощью sttyкоманды.

¹ И традиционно генерировать дамп ядра , но многие системы в настоящее время отключают его по умолчанию.

Жиль "ТАК - перестань быть злым"
источник
SIGINT убивает группу процессов переднего плана, а SIGQUIT убивает ее с помощью дампа ядра. Оба сигнала могут быть обработаны. Я не уверен, что вы имеете в виду, читая следующую команду . Системы не отключают дамп ядра, кроме как установив начальный предел coredumpsize равным 0 (не жесткий, вы обычно можете его повысить).
Стефан Шазелас
@ StéphaneChazelas В программе, которая выполняет взаимодействия с пользователем, обычная семантика SIGINT состоит в том, чтобы отменить текущую пользовательскую команду и позволить пользователю взаимодействовать с программой, то есть вернуться к главному командному циклу. С другой стороны, я не помню, чтобы я видел программу, в которой SIGQUIT не завершается (за исключением ошибок в обработчике сигналов). Действительно, многие системы по умолчанию отключают дампы ядра, устанавливая мягкое ограничение размера дампа ядра на 0, оставляя пользователям свободу изменять эту настройку по умолчанию, если они того пожелают.
Жиль "ТАК - перестань быть злым"
Это исключение. SIGINT убивает текущую задачу. Только несколько приложений расширили бы это, чтобы убить их собственную задачу "переднего плана". Вы должны думать о lessили vim. Обратите внимание, что в cmd | less, CTRL-Cобычно убивает cmd(в то время как lessэто обрабатывается, чтобы отменить текущее действие (например, поиск)) (продолжение)
Стефан Шазелас
Я считаю формулировку вашего ответа запутывающей в этом отношении. Тот факт, что SIGQUIT обычно не обрабатывается, заключается в том, что он не используется таким же образом. Вы нажимаете CTRL-C, чтобы прервать то, что вы в данный момент делаете. Вы будете использовать `CTRL- \` только очень редко для отладки, чтобы генерировать дамп ядра. Как правило, нет причин, по которым приложение хотело бы помешать этому.
Стефан Шазелас
@ StéphaneChazelas Не просто меньше и vim, большинство терминальных приложений, которые читают пользовательские команды для этого. Например, REPL (bash, dash, ksh, zsh, python, irb, fsharpi, Mathematica,…). Это вряд ли необычно. Ваш первый комментарий возражает против того, чтобы рисовать SIGINT и SIGQUIT как слишком разные, а ваш последний комментарий - за то, что он рисует SIGINT и SIGQUIT как слишком похожие, что заставляет меня озадачиться тем, что вы едете.
Жиль "ТАК - перестань быть злым"
7

В дополнение к ответу Жиля позвольте мне добавить, что вы всегда можете вводить непечатаемые символы в bash с помощью Ctrl-v+ key( в данном случае Ctrl-v+ Ctrl+4) и проверять код символа с помощью

$ printf '^\' | od -An -tu    # input ^\ as C-v C-4
28

Вы получите десятичный код символа, который, как вы можете проверить, man asciiсоответствует разделителю файлов (FS) .

jimmij
источник
Итак, что делает Ctrl + V? Я привык к тому, чтобы быть "вставить буфер обмена".
JDługosz
2
@ JDługosz: Ctrl-V говорит терминалу не интерпретировать следующий символ. Вызывает сожаление тот факт, что комбинации клавиш графического интерфейса переняли эти управляющие символы, что приводит к ненужной путанице. Раньше Linux использовал Alt- [Key] для клавиш GUI (например, Alt-C / Alt / V для копирования / вставки), но тогда люди, очевидно, думали, что делать то же самое, что и Windows, было важнее; тем временем пользователи Mac по-прежнему не испытывают проблем с использованием клавиши Command вместо клавиши Ctrl для этих операций.
celtschk
Команда (короче) является: printf '%d\n' '"^\'?
Исаак