Cuando presiona Ctrl+X, su emulador de terminal escribe el byte 0x18 en el lado maestro del par pseudo-terminal.
Lo que sucede a continuación depende de cómo se configura la disciplina de línea tty (un módulo de software en el núcleo que se encuentra entre el lado maestro (bajo el control del emulador) y el lado esclavo (con el que interactúan las aplicaciones que se ejecutan en el terminal).
Un comando para configurar esa disciplina de línea tty es el stty
comando.
Cuando ejecuta una aplicación tonta como cat
esa no es consciente y no le importa si su stdin es una terminal o no, la terminal está en un modo canónico predeterminado donde la disciplina de línea tty implementa un editor de línea cruda .
Algunas aplicaciones interactivas que necesitan más que ese editor de línea cruda suelen cambiar esa configuración al inicio y restaurarla al salir. Los proyectiles modernos, a su solicitud, son ejemplos de tales aplicaciones. Implementan su propio editor de línea más avanzado.
Por lo general, mientras ingresa una línea de comando, el shell coloca la disciplina de línea tty en ese modo, y cuando presiona enter para ejecutar el comando actual, el shell restaura el modo tty normal (como estaba vigente antes de emitir el aviso).
Si ejecuta el stty -a
comando, verá la configuración actual en uso para las aplicaciones tontas . Es probable que vea el icanon
, echo
y echoctl
los ajustes que se habilitó.
Lo que eso significa es que:
icanon
: ese editor de líneas crudas está habilitado.
echo
: los caracteres que escribe (que el emulador de terminal escribe en el lado maestro) se repiten (están disponibles para su lectura por el emulador de terminal).
echoctl
: en lugar de repetirse como asis, los caracteres de control se repiten como ^X
.
Entonces, digamos que escribes A B Backspace-aka-Ctrl+H/? C Ctrl+X Backspace Return.
El emulador de terminal enviará: AB\bC\x18\b\r
. La disciplina de línea hará eco : AB\b \bC^X\b \b\b \b\r\n
y se leerá una aplicación que lee la entrada del lado esclavo ( /dev/pts/x
) AC\n
.
Todo lo que ve la aplicación es AC\n
, y solo cuando presiona Enterpara que no pueda tener ningún control en la salida ^X
allí.
Notarás que para echo , el primero ^H
( ^?
con algunos terminales, ver la erase
configuración) resultó en \b \b
ser enviado de vuelta al terminal. Esa es la secuencia para mover el cursor hacia atrás, sobrescribir con espacio, mover el cursor hacia atrás nuevamente, mientras que el segundo ^H
resultó en \b \b\b \b
borrar esos dos ^
y X
caracteres.
El ^X
(0x18) en sí mismo se estaba traduciendo hacia ^
y X
para la salida. Al igual B
, no llegó a la aplicación, ya que la eliminamos con Retroceso.
\r
(aka ^M
) se tradujo a \r\n
( ^M^J
) para echo, y \n
( ^J
) para la aplicación.
Entonces, ¿cuáles son nuestras opciones para esas aplicaciones tontas ?
- deshabilitar
echo
( stty -echo
). Eso cambia efectivamente la forma en que se hacen eco de los caracteres de control, al ... no hacer eco de nada. Realmente no es una solución.
- desactivar
echoctl
. Eso cambia la forma en que se hacen eco los caracteres de control (que no sean ^H
, ^M
... y todos los demás utilizados por el editor de línea). Luego se repiten tal cual. Es decir, por ejemplo, el carácter ESC se envía como el byte \e
( ^[
/ 0x1b
) (que es reconocido como el inicio de una secuencia de escape por el terminal), ^G
usted envía un \a
(un BEL, haciendo que su terminal emita un pitido) ... No es una opción .
- deshabilitar el editor de línea cruda (
stty -icanon
). No es realmente una opción, ya que las aplicaciones crudas serían mucho menos utilizables.
- edite el código del kernel para cambiar el comportamiento de la disciplina de línea tty para que el eco de un carácter de control envíe en
\e[7m^X\e[m
lugar de solo ^X
(aquí \e[7m
generalmente se habilita el video inverso en la mayoría de los terminales).
Una opción podría ser usar un contenedor como rlwrap
ese es un truco sucio para agregar un editor de línea elegante a aplicaciones tontas. Ese envoltorio en efecto intenta reemplazar los mensajes simples read()
desde el dispositivo terminal a las llamadas al editor de línea readline (que cambian el modo de la disciplina de línea tty).
Yendo aún más lejos, incluso podría probar soluciones como esta que secuestra todas las entradas del terminal para pasar por el editor de línea de zsh (que resalta ^X
s en video inverso) confiando en la :exec
función de la pantalla GNU .
Ahora, para las aplicaciones que implementan su propio editor de línea, depende de ellos decidir cómo se hace el eco . bash
usa readline para aquello que no tiene soporte para personalizar cómo se repiten los caracteres de control.
Para zsh
ver:
info --index-search='highlighting, special characters' zsh
zsh
resalta caracteres no imprimibles de forma predeterminada. Puede personalizar el resaltado con, por ejemplo:
zle_highlight=(special:fg=white,bg=red)
Para resaltar blanco sobre rojo para esos caracteres especiales.
Sin embargo, la representación de texto de esos caracteres no es personalizable.
En una localización UTF-8, 0x18 será mostrado como ^X
, \u378
, \U7fffffff
(dos puntos de código Unicode sin asignar) como <0378>
, <7FFFFFFF>
, \u200b
(un carácter Unicode imprimible no-realidad) como <200B>
.
\x80
en un entorno local iso8859-1 se representaría como ^�
... etc.
bash
estáreadline
manejando esas cosas, y para la mayoría de los demás es el controlador tty.