termios en Python: control seguro del terminal

Publicado el: 25/08/2026
Tempo de leitura: 5 minutos
Laptop displaying code with reflection, perfect for tech and programming themes.

El módulo termios expone el control POSIX de terminales TTY en Unix. Permite activar o desactivar echo, cambiar entre entrada canónica y lectura carácter por carácter, configurar velocidades seriales, gestionar colas y consultar el tamaño de la ventana.

Estas operaciones modifican estado compartido del terminal asociado al file descriptor. Si el programa termina sin restaurarlo, el shell puede quedar sin echo, con teclas de control desactivadas o en un modo aparentemente roto. Guarda siempre los atributos originales y restáuralos en finally.

Disponibilidad

termios solo existe en Unix con soporte POSIX TTY. Windows usa APIs distintas y el descriptor debe estar conectado a un terminal real.

import os
import sys

if not os.isatty(sys.stdin.fileno()):
    raise RuntimeError("stdin no está conectado a un TTY")

La entrada redirigida desde un pipe o archivo no tiene los mismos atributos.

Estructura de tcgetattr()

tcgetattr(fd) devuelve siete elementos:

[iflag, oflag, cflag, lflag, ispeed, ospeed, cc]

Representan flags de entrada, salida, control y comportamiento local, velocidades y caracteres especiales. Interpreta todo mediante constantes simbólicas de termios.

Guardar y restaurar

import sys
import termios

fd = sys.stdin.fileno()
original = termios.tcgetattr(fd)
nuevo = termios.tcgetattr(fd)

try:
    nuevo[3] &= ~termios.ECHO
    termios.tcsetattr(fd, termios.TCSADRAIN, nuevo)
    secreto = input("Contraseña: ")
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, original)
    print()

Haz dos llamadas o una copia profunda porque la lista cc es mutable. Una copia superficial puede compartirla.

Cuándo aplicar cambios

TCSANOW aplica de inmediato. TCSADRAIN espera la salida pendiente. TCSAFLUSH también descarta entrada no leída.

Para desactivar echo en un prompt, TCSADRAIN evita cortar texto ya enviado.

Echo

El bit ECHO controla si los caracteres aparecen en pantalla.

atributos[3] &= ~termios.ECHO

Desactivar echo no vuelve la captura automáticamente segura. Para contraseñas comunes, prefiere getpass.getpass().

Modo canónico

Con ICANON activo, la entrada llega después de Enter y el driver realiza edición básica. Al desactivarlo, las lecturas pueden devolver datos antes de una línea completa.

atributos[3] &= ~termios.ICANON

El modo no canónico sirve para juegos, hotkeys e interfaces en pantalla completa, pero obliga a procesar bytes y secuencias de escape.

VMIN y VTIME

En cc, VMIN y VTIME controlan las lecturas no canónicas.

atributos[6][termios.VMIN] = 1
atributos[6][termios.VTIME] = 0

VMIN 1 y VTIME 0 espera al menos un byte. VMIN 0 con VTIME positivo crea un timeout en décimas de segundo.

Leer una tecla

import os
import sys
import termios

fd = sys.stdin.fileno()
original = termios.tcgetattr(fd)
nuevo = termios.tcgetattr(fd)
nuevo[3] &= ~(termios.ICANON | termios.ECHO)
nuevo[6][termios.VMIN] = 1
nuevo[6][termios.VTIME] = 0

try:
    termios.tcsetattr(fd, termios.TCSADRAIN, nuevo)
    tecla = os.read(fd, 1)
finally:
    termios.tcsetattr(fd, termios.TCSADRAIN, original)

print(tecla)

Una tecla visible puede generar varios bytes. Las flechas y teclas de función producen secuencias de escape.

Unicode

os.read() devuelve bytes. Un carácter UTF-8 puede ocupar varios, por lo que un byte no equivale necesariamente a un carácter.

Usa un decoder incremental o analiza el protocolo del terminal.

Señales y teclas de control

ISIG permite que Ctrl+C y Ctrl+Z generen señales. Desactivarlo convierte esos bytes en entrada normal.

Ofrece otra tecla de salida y restaura el estado tras excepciones. Consulta signal en Python.

Mapeo de entrada

ICRNL, INLCR e IGNCR controlan conversiones entre carriage return y newline. Modificarlos afecta Enter y protocolos seriales.

Cambia solo los bits necesarios.

Procesamiento de salida

OPOST habilita transformaciones de salida. Un modo raw puede desactivarlo, alterando también el comportamiento de newline y cursor.

Para casos comunes, usa funciones de tty o una biblioteca de terminal completa.

Flags de hardware

cflag incluye tamaño de carácter, paridad, stop bits y control de flujo. Son importantes en puertos seriales.

Una configuración incorrecta puede producir datos ilegibles o bloquear la comunicación.

Baud rate

ispeed y ospeed usan constantes como B9600 y B115200.

atributos[4] = termios.B115200
atributos[5] = termios.B115200

No todas las velocidades están disponibles. Para producción, pyserial suele ser más portable.

tcdrain()

tcdrain(fd) espera que toda la salida en cola se transmita. Es útil antes de cambiar parámetros o cerrar un dispositivo serial.

Puede bloquear si el hardware está lento o desconectado.

tcflush()

termios.tcflush(fd, termios.TCIFLUSH)

TCIFLUSH descarta entrada, TCOFLUSH salida y TCIOFLUSH ambas. Descartar salida puede perder comandos ya aceptados.

Control de flujo

tcflow() suspende o reanuda entrada o salida con acciones como TCOOFF y TCOON. No lo confundas con control de flujo de hardware.

Enviar break

tcsendbreak(fd, duration) envía una condición break en líneas seriales. Duración cero significa aproximadamente 0,25 a 0,5 segundos; otros valores dependen del sistema.

Tamaño de ventana

Desde Python 3.11, tcgetwinsize() devuelve filas y columnas.

filas, columnas = termios.tcgetwinsize(sys.stdout.fileno())
print(filas, columnas)

tcsetwinsize() establece el tamaño cuando la plataforma lo soporta, algo útil con pseudo-terminales.

SIGWINCH

Después de un resize, procesos Unix suelen recibir SIGWINCH. Haz que el handler marque una flag y recalcula el layout en el loop principal.

El conjunto final sobre curses cubre interfaces de pantalla completa.

Context manager reutilizable

from contextlib import contextmanager
import termios

@contextmanager
def atributos_temporales(fd, modificar):
    original = termios.tcgetattr(fd)
    nuevo = termios.tcgetattr(fd)
    modificar(nuevo)
    try:
        termios.tcsetattr(fd, termios.TCSADRAIN, nuevo)
        yield
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, original)

Centralizar la restauración reduce rutas de error olvidadas.

Fork y subprocesses

Los hijos pueden heredar el mismo terminal y observar atributos temporales. Evita iniciar procesos ajenos mientras el TTY está modificado.

Usa un pseudo-terminal cuando necesites aislar una aplicación interactiva.

Threads

El estado pertenece al terminal, no al thread. Dos threads cambiando flags pueden restaurar valores fuera de orden. Centraliza el control en uno solo.

Recuperación manual

Si una aplicación deja el terminal sin echo, stty sane suele restaurar un estado razonable. Documenta el comando en herramientas experimentales.

Pruebas

Prueba terminal real y entrada redirigida, Ctrl+C, excepción durante lectura, Unicode, flechas, resize, subprocesses, serial, VMIN/VTIME y restauración tras fallo.

Usa pty para tests automatizados, pero también prueba manualmente.

Errores comunes

Los fallos frecuentes son omitir finally, modificar la lista original, hacer copia superficial de cc, asumir una tecla por byte, desactivar ISIG sin salida alternativa, operar sobre stdin redirigido y cambiar demasiadas flags.

Conclusión

termios proporciona control preciso de terminales POSIX y puertos seriales. Úsalo cuando necesites flags de bajo nivel; para tareas comunes, prefiere tty, getpass, curses o bibliotecas especializadas.

Guarda y restaura el estado, cambia solo los bits necesarios y prueba en el Unix objetivo. Consulta la documentación oficial de termios y termios(3).

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Código Python para representar fracciones exactas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: convierte números en fracciones

    Aprende fractions.from_number en Python para convertir números en fracciones exactas, controlar precisión, validar entradas y evitar redondeos inesperados.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026
    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026