Caracteres de controle ASCII no meu terminal

Caracteres de controle ASCII no meu terminal


Olá! Eu tenho pensado muito no terminal e ontem fiquei curioso sobre todos esses “códigos de controle”, como Ctrl-AAssim, Ctrl-CAssim, Ctrl-Wetc. Qual é o problema com todos eles?

Uma tabela de caracteres de controle ASCII

Aqui está uma tabela de todos os 33 caracteres de controle ASCII e o que eles fazem na minha máquina (no Mac OS), mais ou menos. Existem cerca de um milhão de advertências, mas vou falar sobre o que isso significa e todos os problemas com este diagrama que eu conheço.

Caracteres de controle ASCII no meu terminal

Você também pode visualizá -lo como uma página HTML (acabei de fazer uma imagem para que ela aparecesse no RSS).

Diferentes tipos de códigos são misturados

A primeira coisa surpreendente sobre esse diagrama para mim é que existem 33 códigos de controle, divididos em (muito falando) essas categorias:

  1. Códigos que são tratados pelo driver de terminal do sistema operacional, por exemplo, quando o sistema operacional vê um 3 (Ctrl-C), ele enviará um SIGINT sinal para o programa atual
  2. Todo o resto é passado para o aplicativo AS-IS e o aplicativo pode fazer o que quiser com eles. Algumas subcategorias daquelas:
    • Códigos que correspondem a uma tecla literal de uma chave no teclado (EnterAssim, TabAssim, Backspace). Por exemplo, quando você pressiona Enterseu terminal é enviado 13.
    • Códigos usados ​​por readline: “O aplicativo pode fazer o que quiser” geralmente significa “fará mais ou menos o que o readline biblioteca, se o aplicativo realmente usa readline ou não ”, então eu rotulei um monte de códigos que readline usos
    • Outros códigos, por exemplo, eu acho Ctrl-X não tem significado padrão no terminal em geral, mas o Emacs o usa muito fortemente

Não existe uma estrutura real para quais códigos estão em quais categorias eles são apenas espalhados aleatoriamente porque isso evoluiu organicamente.

(Se você está curioso sobre o ReadLine, escrevi mais sobre o ReadLine ao inserir texto no terminal é complicado, e há muitas folhas de trapaça por aí)

Existem apenas 33 códigos de controle

Outra coisa que acho um pouco surpreendente é que são apenas 33 códigos de controle – A a Z, mais 7 mais (@, (, \, ), ^, _, ?). Isso significa que, se você quiser ter, por exemplo Ctrl-1 Como atalho de teclado em um aplicativo de terminal, isso não é realmente significativo – no meu pela máquina, pelo menos Ctrl-1 é exatamente a mesma coisa que apenas pressionar 1Assim, Ctrl-3 é o mesmo que Ctrl-(etc.

Também Ctrl+Shift+C Não é um código de controle – o que ele faz depende do seu emulador de terminal. No Linux Ctrl-Shift-X é frequentemente usado pelo emulador de terminal para copiar ou abrir uma nova guia ou colar, por exemplo, ele não é enviado para o TTY.

Também eu uso Ctrl+Left Arrow O tempo todo, mas isso não é um código de controle, em vez disso, envia uma sequência de escape ANSI (ctrl-((1;5D) que é uma coisa diferente para a qual absolutamente não temos espaço neste post.

Essa coisa de “há apenas 33 códigos” é totalmente diferente de como os atalhos do teclado funcionam em uma GUI onde você pode ter Ctrl+KEY Para qualquer chave que você quiser.

Os nomes oficiais da ASCII não são muito significativos para mim

Cada um desses 33 códigos de controle tem um nome em ASCII (por exemplo 3 é ETX). Quando todos esses códigos de controle foram originalmente definidos, eles não estavam sendo usados ​​para computadores ou terminais, eles foram usados ​​para a máquina Telegraph. As máquinas de telégrafo não são as mesmas que os terminais do UNIX, então muitos códigos foram reaproveitados para significar outra coisa.

Pessoalmente, não acho esses nomes ASCII muito úteis, porque 50% das vezes o nome no ASCII não tem uma relação real com o que esse código faz nos sistemas Unix hoje. Portanto, é mais fácil ignorar completamente os nomes ASCII, em vez de tentar descobrir quais ainda correspondem ao seu significado original.

É difícil usar o Ctrl-M como um atalho de teclado

Outra coisa que é um pouco estranha é que Ctrl-M é literalmente o mesmo que
Entere Ctrl-I é o mesmo que Tabo que dificulta o uso desses dois como atalhos de teclado.

De algumas pesquisas rápidas, parece que algumas pessoas ainda usam Ctrl-I e
Ctrl-M Como atalhos de teclado (aqui está um exemplo), mas para fazer isso, você precisa configurar seu emulador de terminal para tratá -los de maneira diferente do padrão.

Para mim, o principal argumento é que, se eu escrever um aplicativo de terminal, devo evitar Ctrl-I e Ctrl-M como atalhos de teclado nele.

Como identificar quais códigos de controle são enviados

Enquanto escrevia isso, eu precisava fazer um monte de experimentos para descobrir o que várias combinações importantes fizeram, então escrevi este script python eco-key.py que as imprimirá.

Provavelmente há uma maneira mais oficial, mas eu apreciei ter um script que eu poderia personalizar.

Advertência: no modo canônico vs não canônico

Dois desses códigos (Ctrl-W e Ctrl-U) são rotulados na tabela como “tratados pelo sistema operacional”, mas na verdade eles não são sempre Mandido pelo sistema operacional, depende se o terminal está no modo “canônico” ou no “modo não canônico”.

No modo canônico, os programas só recebem entrada quando você pressiona Enter (e o sistema operacional é responsável por excluir caracteres quando você pressiona Backspace ou Ctrl-W). Mas no modo não canônico, o programa recebe entrada imediatamente quando você pressiona uma tecla e o Ctrl-W e Ctrl-U Os códigos são passados ​​para o programa para lidar com a maneira como desejar.

Geralmente no modo não canônico, o programa lida Ctrl-W e Ctrl-U
Da mesma forma como o sistema operacional, mas existem algumas pequenas diferenças.

Alguns exemplos de programas que usam o modo canônico:

  • provavelmente praticamente qualquer programa não interativo, como grep ou cat
  • gitEu penso

Exemplos de programas que usam modo não canônico:

  • python3Assim, irb e outros repls
  • sua concha
  • qualquer tui de tela inteira gosta less ou vim

Advertência: todos os códigos do “driver do terminal do sistema operacional” são configuráveis ​​com stty

Eu disse isso Ctrl-C envia SIGINT Mas tecnicamente isso não é necessariamente verdadeiro, se você realmente deseja, pode remapear todos os códigos rotulados como “Driver do terminal do sistema operacional”, além de backspace, usando uma ferramenta chamada sttye você pode ver os mapeamentos com stty -a.

Aqui estão os mapeamentos da minha máquina agora:

$ stty -a
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = ;
	eol2 = ; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
	min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
	stop = ^S; susp = ^Z; time = 0; werase = ^W;

Pessoalmente, nunca remaguei nada disso e não consigo imaginar uma razão pela qual eu (acho que seria uma receita de confusão e desastre para mim), mas perguntei ao Mastodon e as pessoas disseram que os motivos mais comuns que usaram usaram
stty eram:

  • consertar um terminal quebrado com stty sane
  • definir stty erase ^H Para mudar como funciona o backspace
  • definir stty ixoff
  • Algumas pessoas até mapeiam SIGINT para uma chave diferente, como o deles DELETE chave

Advertência: em sinais

Duas advertências de sinais:

  1. Se o ISIG O modo terminal está desligado e o sistema operacional não enviará sinais. Por exemplo vim desliga ISIG
  2. Aparentemente no BSDS, há um código de controle extra (Ctrl-T) que envia SIGINFO

Você pode ver quais modos de terminal um programa está definindo usando strace assim, os modos de terminal são definidos com o ioctl Chamada do sistema:

$ strace -tt -o out  vim
$ grep ioctl out | grep SET

Aqui estão os modos vim define quando começa (ISIG e ICANON estão faltando!):

17:43:36.670636 ioctl(0, TCSETS, {c_iflag=IXANY|IMAXBEL|IUTF8,
c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST, c_cflag=B38400|CS8|CREAD,
c_lflag=ECHOK|ECHOCTL|ECHOKE|PENDIN, ...}) = 0

e redefine os modos quando sai:

17:43:38.027284 ioctl(0, TCSETS, {c_iflag=ICRNL|IXANY|IMAXBEL|IUTF8,
c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD,
c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE|PENDIN, ...}) = 0

Eu acho que a combinação específica de modos que Vim está usando aqui pode ser chamada de “modo bruto”, o Man CfmakerAw fala sobre isso.

Existem muitos conflitos

Relacionado a “Existem apenas 33 códigos”, existem muitos conflitos em que diferentes partes do sistema desejam usar o mesmo código para coisas diferentes, por exemplo, por padrão Ctrl-S irá congelar sua tela, mas se você desligar isso então readline vai usar Ctrl-S Para fazer uma pesquisa a termo.

Outro exemplo é que às vezes na minha máquina Ctrl-T Vai enviar SIGINFO
E às vezes transporá 2 caracteres e às vezes fará algo completamente diferente, dependendo de:

  • se o programa tem ISIG definir
  • Se o programa usa readline / imita o comportamento da readline

Advertência: no “backspace” e “outro backspace”

Neste diagrama, rotulei o código 127 como “backspace” e 8 como “outro backspace”. Uh, o quê?

Eu acho que este foi o maior tópico de discussão nas respostas sobre Mastodon – aparentemente há muita história nisso e nunca tinha ouvido falar disso antes.

Primeiro, eis como funciona na minha máquina:

  1. Eu pressiono o Backspace chave
  2. O TTY é enviado o byte 127que é chamado DEL em ASCII
  3. o driver do terminal do sistema operacional e o readline têm 127 mapeado para o “backspace” (para que funcione no modo canônico e no modo não canônico)
  4. O personagem anterior é excluído

Se eu pressionar Ctrl+Htem o mesmo efeito que Backspace Se estou usando o ReadLine, mas em um programa sem suporte à readline (como cat por exemplo), ele apenas imprime ^H.

Aparentemente, a etapa 2 acima é diferente para algumas pessoas – seus Backspace Key envia o byte 8 em vez de 127e se eles querem que o backspace funcione, precisam configurar o sistema operacional (usando stty) para definir erase = ^H.

Há uma seção incrível do Manual de Política Debian na configuração do teclado que descreve como Delete e Backspace deve funcionar de acordo com a política do Debian, que parece muito semelhante à forma como funciona no meu Mac hoje. Meu entendimento (através deste post Mastodon) é que essa política foi escrita nos anos 90, porque havia muita confusão sobre o que Backspace Deveria fazer nos anos 90 e precisava haver um padrão para fazer tudo funcionar.

Há um monte de coisas terminais mais históricas aqui, mas é tudo o que vou dizer por enquanto.

Provavelmente há muito mais diversidade em como isso funciona

Provavelmente perdi um monte de mais maneiras de que “como funciona na minha máquina” pode ser diferente de como funciona nas máquinas de outras pessoas, e provavelmente cometi alguns erros sobre como isso também funciona na minha máquina. Mas isso é tudo o que tenho hoje.

Mais algumas coisas que sei que deixei de fora: de acordo com stty -a Ctrl-O é “descarte”, Ctrl-R é “reimpressão” e Ctrl-Y é “dsusp”. Eu não tenho idéia de como fazer isso realmente fazer qualquer coisa (pressioná -los não faz nada óbvio, e algumas pessoas me disseram o que costumavam fazer historicamente, mas não está claro para mim se tiverem um uso em 2024), e na maioria das vezes na prática eles parecem ser transmitidos para o aplicativo de qualquer maneira, então eu apenas rotulou Ctrl-R e Ctrl-Y como
readline.

Nem tudo isso é útil para saber

Também quero dizer que acho que o conteúdo deste post é meio interessante, mas não acho que sejam necessariamente que útil. Eu usei o terminal com bastante sucesso todos os dias nos últimos 20 anos sem saber literalmente nada disso – eu apenas sabia o que Ctrl-CAssim, Ctrl-DAssim, Ctrl-ZAssim, Ctrl-RAssim,
Ctrl-L fez na prática (mais talvez Ctrl-AAssim, Ctrl-E e Ctrl-W) e não se preocupei com os detalhes na maior parte, e isso quase sempre era totalmente bom, exceto quando eu estava tentando usar o XTERM.JS.

Mas eu me diverti aprendendo sobre isso, então talvez seja interessante para você também.



Postagens Similares

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *