cc0luism@uco.es
Conocer cómo funciona la interacción entre un ordenador UNIX y los
diferentes tipos de terminales desde los que podemos conectarnos a él
no es fundamental para el usuario medio, pero sí es interesante para
resolver algunos tipos de problemas habituales, para saber para qué
sirve la variable TERM
, etc. Este es un tema relativamente complejo
y sobre el que existe poca documentación clara y asequble, de ahí el
motivo de este documento.
Es interesante, en primer lugar, hacer notar la diferencia entre el trabajo
en un PC y en UNIX. En un PC el teclado, la pantalla y el ratón forman
parte de la máquina misma, de forma que el ordenador controla todos
ellos y sabe perfectamente qué tecla se ha pulsado en cada momento o
cómo controlar la pantalla. Aunque también en este entorno pueden
surgir problemas de configuración, siempre serán menos numerosos
que en UNIX.
Cuando trabajamos en UNIX o en cualquier otro sistema operativo
multiusuario, nuestro teclado y nuestra pantalla no suelen estar
conectados fisicamente al ordenador, salvo en el caso de las versiones
UNIX de PC o estaciones gráficas; pero incluso en esos casos, si
nos conectamos a otros ordenadores, empiezan a surgir los temas
de los que vamos a hablar aquí.
Partamos del caso más simple, que aunque era el más utilizado en los primeros tiempos de UNIX (y por tanto es el que orientó a sus diseñadores en la forma de gestionar terminales), hoy no es el más habitual. Me refiero a un simple terminal "tonto" (también llamados terminales ASCII, terminales VT, dumb terminals, etc) conectado mediante un cable serie RS232 al propio ordenador. Por un cable serie sólo viajan bytes, uno detrás de otro, tanto en dirección del terminal al ordenador (cosa que ocurre cuando pulsamos las teclas) como en el sentido contrario (caso de lo que sale por pantalla). Veamos qué ocurre cuando pulsamos una tecla normal, como la de la letra "a":
stty
). Más adelante hablaremos de esto. El caso más
normal es que el byte que ha llegado se entregue al programa que
se está ejecutando en el terminal y asimismo se devuelva por el cable
serie al terminal (eco). Este al ver que llega el byte 97, ve que
corresponde al código ASCII de la letra "a" y hace aparecer ese carácter
por la pantalla. Un caso en que no ocurre así en cuando al conectarnos
se nos pide la clave y vemos que al escribirla no aparece por la pantalla.
Es así porque el programa encargado de pedir el nombre de usuario y
la clave (el programa login) cuando pide la clave desactiva el
parámetro eco del terminal.
Ya hemos dicho que todo lo que pulsamos en el teclado y todo lo que el ordenador envía a nustra pantalla viajan por el mismo cable serie. Aunque nos conectemos a través de red local y por tanto no exista ese cable serie, ocurre lo mismo, en el sentido de que existe un único canal lógico bidireccional entre nuestro teclado y pantalla y el ordenador. Ya hemos explicado también el proceso que ocurre cuando pulsamos una tecla como la letra "a". Lo mismo sucede al pulsar cualquier otra tecla que corresponda a un carácter incluido en el código ASCII. Surgen ahora dos dificultades:
Un inconveniente del código ASCII es que define códigos numéricos de un byte para los caracteres. Esto da un máximo de 265. Teniendo en cuenta que históricamente los canales de comunicación que se usaban usaban sólo 7 bits en vez de 8, y que este código se definió para acomodarse a cualquier canal, sólo usa 7 bits, lo que permite un máximo de 128 caracteres. De ellos, no todos corresponden a letras; también hay códigos especiales como el espacio (32), el salto de línea (10), el retorno de carro (13), el salto de página (12), y muchos otros. Por tanto los únicos caracteres que contempla este código son las letras mayúsculas y minúsculas, los dígitos (0 a 9) y pocos más. Eso es suficiente para el idioma inglés, pero no es suficiente para muchos otros idiomas. En particular los caracteres españoles como letras acentuadas, ñ, interrogación y admiración abiertas, no están en ese código. Para suplir estas deficiencias, se definieron otros códigos para contemplar otros idiomas. Uno de los más extendidos es el ISO 8859/1, también llamado ISO Latin 1. Es éste un código de 8 bits (por tanto soporta hasta 256 códigos) que incluye los mismos que ASCII más los caracteres usados por la mayoría de los lenguajes occidentales. Casi todas las variantes de UNIX usan internamente este código; entonces, ¿ qué problema hay ?. Por un lado, el teclado que estemos usando debe estar correctamente configurado para que cuando yo pulse la secuencia de teclas que componen la "á" ("a" acentuada): ' seguido de a, genere el código ISO Latin 1 y envíe el ordenador ese código. Eso se hace:
Basta con configurarlas indicándoles que usen el teclado español.
Sea cual sea la forma en que nos conectemos desde un
PC a UNIX (existen varias), el PC se debe configurar para que use
teclado español (normalmente con el comando keyb
).
En este caso es responsabilidad de los administradores de sistemas su correcta configuración, que es algo más compleja.
stty
. Este caso concreto se
arregla con el comando:
stty -istrip cs8
Las teclas de movimiento del cursor o las teclas de función no tienen
ningún código asignado. De hecho al pulsar una de esas teclas se generan
varios bytes que viajan por la línea de comunicación al ordenador.
Este debe reconocer esa secuencia y saber qué tecla hemos pulsado. El
primer byte de la secuencia siempre es el mismo, el 27 (ESC). Cuando
el programa que estemos usando recibe un código 27, sabe que probablemente
hemos pulsado una tecla especial, y por tanto analiza los códigos
siguientes para saber qué tecla es. El problema aquí es que no todos los
terminales tienen las mismas teclas y la misma tecla en distintos
terminales no siempre genera los mismos códigos en todos ellos.
Aquí existe infinidad
de terminales de distintas marcas y no es posible establecer un estandar
como ASCII o ISO Latin 1.
Esto se resuelve en UNIX mediante una pequeña base de datos que contiene
las secuencias de las teclas especiales para muchos tipos de terminales.
Esta base de datos figura tradicionalmente en el fichero /etc/termcap
(de terminal capabilites) y en los UNIX derivados de System V
en el sistema llamado terminfo.
Los programas que usan las teclas especiales (como los editores y los
programas que usan menús) necesitan saber qué tipo de terminal tenemos,
para obtener la información que necesita de esa base de datos. Esto lo
hace obteniendo el valor de la variable TERM
. Si ésta contiene
el valor vt220
, el programa leerá al principio de su ejecución
de la base de datos la información sobre ese terminal para saber qué
códigos generan sus teclas especiales y así poder reconocerlas cuando
las reciba (en esa base de datos no sólo hay información sobre el teclado
sino también sobre los códigos de manejo de la pantalla, como veremos
más adelante).
He aquí la explicación del sentido y la importancia de la variable TERM
.
El usuario debe preocuparse de que se corresponda con el tipo de terminal
que realmente tiene; si no es así, las aplicaciones a pantalla completa
no funcionarán bien. En la Universida de Córdoba está implantado el
Sistema LOGIN que configura la entrada de cada usuario a los
sistemas UNIX y que tiene en cuenta entre otras cosas este aspecto, por
lo que es difícil que surjan problemas de este tipo.
Con la pantalla ocurre algo parecido al teclado. Cuando un programa
que funcione a toda pantalla (como editores, programas con menús, etc)
necesita borrar la pantalla o poner una línea en video inverso debe
enviar una secuencia de códigos a la misma (a través de la línea de
comunicación que existe entre nosotros y el ordenador). Como ya habrás
adivinado, estos códigos no son iguales para todos los tipos de terminales.
El programa debe saber, también a través de la variable TERM
la terminal
que estamos usando para leer de la base de datos de terminales (sea
/etc/termcap
o terminfo) los códigos de manejo de nuestra
pantalla.
Muchas veces ocurre que al ejecutar un editor la pantalla se llena de
caracteres raros o desordenados. La causa más común es que la variable
TERM
no tenga el valor correcto.
Ya hemos dicho en un par de ocasiones que el driver de terminales
tiene unos parámetros que se pueden configurar. A la forma en que
funciona según esos parámetros se conoce con el nombre de
disciplina de línea, y el comando stty
sirve para modificar
su comportamiento. Ya hemos indicado que en el sistema operativo existe
un único driver para cada tipo de dispositivo, por tanto sólo existe
uno para controlar todas las terminales. Sin embargo cada terminal
tiene su propio conjunto de parámetros, es decir, su propia
disciplina de línea, y cada usuario puede ejecutar el comando
stty
para cambiar la suya. Pongamos un ejemplo:
Supongamos que hemos escrito un programa en el que en un momento dado
pedimos al usuario que introduzca algún dato por el teclado. Esto
es muy común y en el lenguaje C se suele hacer mediante una función
como scanf
o gets
. Cuando el usuario está ejecutando el programa
y llega a este punto, escribe lo que se le pide. Supongamos que se
equivoca y tiene que usar la tecla de borrado para hacer las correcciones.
En cuanto pulsa la tecla INTRO, lo que ha escrito es recibido por el
programa. Hay que hacer notar varias cosas:
^u
, por ejemplo, significa pulsar la tecla Control
y la u
):
erase
(^h
o ^?
)Es la tecla que sirve para borrar los últimos caracteres escritos.
kill
(^u
)Es la tecla que sirve para anular toda la línea que llevamos escrita hasta el momento.
intr
(^c
)Es la tecla que, cuando es recibida por el driver, corta el programa que se esté ejecutando en el terminal.
^u
. El parámetro que debe cambiar
más a menudo el usuario es el de la tecla de borrado (erase
), debido
a que algunos terminales generan un código al pulsar la tecla de borrado
y otros generan otro diferente; unos generan el código 8 (^h
) y
otros el 127 (^?
). Si el driver está configurado para que la
tecla de borrado sea ^?
y nos conectamos desde una terminal cuya
tecla de borrado genera el código 8 ^h
, cuando queramos borrar
ocurrirá lo siguiente:
en un lugar da^HVemos que al intentar borrar la letra "a" para poner una "e", en vez de borrarse aparece el código generado por nuestra tecla de borrado, que no es el que espera el driver para borrar. Igualmente sucede a menudo el caso contrario: el driver tiene configurada para borrar la tecla que genera el 8 (
^h
) y la tecla de borrar de
nuestro terminal genera el 127 (^?
). Entonces aparecería:
en un lugar da^?Esto ocurre a menudo porque hay gran cantidad de terminales de ambos tipos. La forma de solucionarlo es la siguiente:
stty erase <-Donde hemos puesto
<-
para indicar que ahí se pulsa nuestra tecla
de borrado. Si esto ocurre a menudo o siempre que nos conectamos, podemos
poner una de las dos líneas siguientes en nuestro fichero .cshrc
:
stty erase "^h" stty erase "^?"De esta forma, literalmente, también se puede hacer, pero aquí tenemos que conocer el código que genera nuestra tecla de borrado. De la misma forma podemos cambiar los caracteres para las operaciones
kill
o intr
.termio
o de termios
, según la versión.
La librería curses
incluye muchas funciones para situar el
cursor en pantalla, crear ventanas, etc. Ver su página de manual para
más información.
Un caso que no se explica con esto son los programas como muchos juegos,
en los que el programa no está esperando hasta que el usuario pulse
algo desde el teclado, sino que la acción sucede continuamente y el
usuario pulsa ocasionalmente teclas para diversas acciones. Un programa
de este tipo por supuesto debe enular el parámetro que hace que la
entrada del usuario sólo se reciba cuando éste pulsa INTRO (como
los editores, programas de menú, etc), sino también tener la posibilidad
de averiguar regularmente si el usuario ha pulsado algo, y si no seguir
con lo que esté haciendo. Este no es un problema ya de terminales
sino de la función del sistema operativo que se esté usando para leer
la entrada del terminal. Normalmente estas funciones se quedan esperando
hasta que el driver de terminales entregue algo (o sea, hasta que el
usuario pulse alguna tecla o INTRO, según sus parámetros). El
comportamiento que nos interesa en este caso se llama
lectura no bloqueante,
y existen distintos mecanismos en UNIX para utilizarlo.
Otra de las cosas de las que se encarga el driver de terminales
es el control de flujo, entendido aquí como la posibilidad del usuario
de interrumpir momentaneamente la salida a pantalla (por ejemplo, si ésta
es muy abundante y no da tiempo a leerla) y hacer luego que continue.
Hay dos caracteres para eso, que mencionamos junto con sus nombres
para el comando stty
(entre paréntesis, sus valores por defecto):
stop
(^s
)Al pulsar esa tecla, la salida a pantalla se detiene.
start
(^q
)Al pulsarla, se desbloqeua la salida.
^s
y piensan que la pantalla se ha bloqueado.
Cuando ocurra este síntoma, lo primero que se debe intentar es pulsar
^q
.
stty
stty -a
Nos informa de todos los parámetros actuales
de nuestra terminal. Al principio salen las teclas asignadas y algunos
otros valores. A continuación, algunos parámetros que pueden estar
activados o no. Si no lo están, aparecen con un guión delante. Así,
icanon
indica que ese parámetro está activado, pero -istrip
indica que este otro no lo está.
stty echo
, stty -echo
La opción -echo
sirve para desactivar el eco al terminal. Esto
se explicó al principio de este documento. La opción echo
vuelve
a activarlo. Esto se puede usar desde una shell-script que tenga
que pedir una clave y que ésta no aparezca en pantalla.
stty -istrip cs8
Este caso ya lo comentamos antes. Se usa cuando sospechamos que el driver está funcionando a 7 bits en vez de a 8. El síntoma es que no vemos caracteres acentuados, ñ, etc, ni tampoco podemos escribirlos.
stty rows 24 cols 80
Con eso indicamos el tamaño de la pantalla. Sólo es necesario a veces,
sobre todo al conectarnos a otro ordenador si al usar un editor no
sale bien (en ese caso, por supuesto lo primero que hay que mirar es que
la variable TERM
tenga el valor adecuado).
stty
para
adecuar a nuestro gusto la disciplina de línea de nuestro terminal.
En la página de manual del comando (así como en las de termio
o
termios
) se mencionan todas las opciones. Vamos a comentar ahora
algunas de las más usuales.
También hemos dicho que los editores y otros programas a toda pantalla
alteran la disciplina de línea para leer inmediatamente las pulsaciones
del usuario. Cuando uno de estos programas termina, debe dejar el
terminal en el estado en el que estaba inicialmente, que es el adecuado
para el uso de una shell interactiva. Sin embargo, puede que el programa
aborte repentinamente o lo cortemos con ^c
. En ese caso la terminal
no queda en el estado apropiado. Síntomas típicos son que no vemos
lo que escribimos, que al pulsar INTRO el indicador de la
shell aparece al lado y no en la línea siguiente, etc. La forma
de arreglarlo es:
^j stty sane^jExactamente esa secuencia, sin pulsar INTRO hasta después de ella. El comando
stty sane
pone al terminal en un estado "sano". El
^j
es porque UNIX usa el código 10 como salto de línea, por tanto
es el código que espera para aceptar una orden. La tecla INTRO
suele generar el 13, y una de las cosas que hace el driver de
terminales es cambiarlo por un 10. Como en este caso el driver
se ha quedado "indispuesto", tampoco hace eso. Al pulsar ^j
generamos directamente un carácter 10.
Como hemos dicho, la conexión por terminales asíncronos conectados
directamente al ordenador no es actualmente lo más habitual.
Aunque todo lo dicho hasta ahora se aplica a cualquier tipo de
conexión con un sistema UNIX, vamos a comentar algunas
peculiaridades de otros tipos de conexión.
Un emulador de terminal es un programa que nos permite trabajar
como si estuviéramos en una terminal pero sin estarlo. Por ejemplo,
un PC no es un terminal en el sentido que hemos considerado hasta
ahora, es decir, cada tecla no envía un código y la pantalla no
se gestiona con códigos, sino directamente por los programas que
se ejecutan en el PC. Cuando conectamos el PC a un ordenador UNIX
por red local o mediante un cable serie, se necesita un programa
que "simule" el comportamiento de una terminal. Además deben
simular a un tipo de terminal más o menos estandar, uno que esté
registrado en la base de datos de terminales de los sistemas
UNIX, como ya mencionamos. Ejemplos de estos programas
para PC son Kermit, ProComm, HyperTerminal, etc.
Casi todos ellos simulan a terminales VT (vt100, vt200, etc) que
son los más ampliamente utilizados. Por tanto, al conectarnos
con ellos a UNIX, si la terminal no funciona correctamente habrá
que poner el valor de la variable TERM
a vt110
o
vt200
probablemente. Estos programas suelen tener una
configuración en la que podemos elegir el tipo de emulación, así
como otros parámetros como si deben funcionar a 7 u 8 bits, qué
código genera la tecla de borrado (suelen dar dos opciones:
BS, que es el código 8 o ^h
y DEL, que es el 127 o
^?
).
En una terminal X o en una estación gráfica ocurre lo mismo. En este
caso se suelen usar los programas xterm
o cmdtool
(éste
último es propio de los ordenadores SUN). Los valores que debe tomar
la variable TERM
en estos casos es xterm
y sun-cmd
,
respectivamente. Al ejecutar uno de estos programas, la variable
TERM
se pone automaticamente, por lo que no hay problema. Pero
si luego nos conectamos a otro ordenador con rlogin, su
valor se perderá y puede que haya que ponerlo.
El programa telnet está disponible en muchos tipos de ordenadores y sistemas operativos diferentes; permite que nos conectemos a través de una red local a otro ordenador, normalmente UNIX (también podemos conectarnos por telnet a otros tipos de sistemas operativos). rlogin es semejante, sin embargo es practicamente exclusivo de UNIX. En primer lugar, hay que decir que rlogin nos conecta a otro ordenador a 7 bits. Esto significa que los caracteres acentuados, ñ, etc no podremos verlos ni escribirlos. Para que se conecte a 8 bits hay que ejecutar:
rlogin ordenador -8
pp Lo único que comentaremos aquí es que puede haber problemas con los caracteres especiales debidos no sólo a los factores comentados en este documento, sino relacionados con tipos de letra y configuración de teclados, que en estos casos es algo complicada. Si surgen este tipo de problemas, deben ponerse en contacto con los administradores de sistemas.