The termios module exposes POSIX terminal control on Unix. It can enable or disable echo, switch between canonical line input and character-at-a-time reads, configure serial speeds, manage input and output queues, and query the terminal window size.
These operations change shared state on the terminal associated with a file descriptor. If a program exits without restoring that state, the user’s shell may remain without echo, with disabled control keys, or in an apparently broken mode. Always save the original attributes and restore them in finally.
Availability
termios is available only on Unix systems with POSIX TTY support. Windows uses different APIs, and the descriptor must refer to a real terminal.
import os
import sys
if not os.isatty(sys.stdin.fileno()):
raise RuntimeError("stdin is not connected to a TTY")
Piped or file-redirected input does not have ordinary terminal attributes. Detect the situation before applying changes.
The tcgetattr() structure
tcgetattr(fd) returns seven elements:
[iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
The values represent input flags, output flags, control flags, local flags, input speed, output speed, and control characters. Interpret them only through symbolic constants from termios.
Save and restore
import sys
import termios
fd = sys.stdin.fileno()
original = termios.tcgetattr(fd)
updated = termios.tcgetattr(fd)
try:
updated[3] &= ~termios.ECHO
termios.tcsetattr(fd, termios.TCSADRAIN, updated)
secret = input("Password: ")
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, original)
print()
Call tcgetattr() twice or deep-copy the result because the cc list is mutable. A shallow copy can share the nested list.
When changes take effect
TCSANOW applies immediately. TCSADRAIN waits until queued output is transmitted. TCSAFLUSH also discards unread input.
For password prompts, TCSADRAIN avoids cutting output already written. Use TCSAFLUSH only when dropping pending keystrokes is intentional.
Echo
The ECHO bit controls whether typed characters appear.
attributes[3] &= ~termios.ECHO
Disabling echo does not make password collection automatically secure. Privileged processes and the program itself can still access the value. Prefer getpass.getpass() for ordinary passwords.
Canonical mode
With ICANON enabled, input is delivered after Enter and the terminal driver performs basic line editing. Disabling it allows reads before a full line is complete.
attributes[3] &= ~termios.ICANON
Non-canonical mode is useful for games, hotkeys, and full-screen interfaces, but the application must process bytes and escape sequences itself.
VMIN and VTIME
In the cc array, VMIN and VTIME control non-canonical reads.
attributes[6][termios.VMIN] = 1
attributes[6][termios.VTIME] = 0
VMIN 1 and VTIME 0 waits for at least one byte. VMIN 0 with a positive VTIME creates a timeout measured in tenths of a second. POSIX defines several combinations; test the actual target system.
Read one key event
import os
import sys
import termios
fd = sys.stdin.fileno()
original = termios.tcgetattr(fd)
updated = termios.tcgetattr(fd)
updated[3] &= ~(termios.ICANON | termios.ECHO)
updated[6][termios.VMIN] = 1
updated[6][termios.VTIME] = 0
try:
termios.tcsetattr(fd, termios.TCSADRAIN, updated)
key = os.read(fd, 1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, original)
print(key)
A visible key can generate several bytes. Arrow and function keys normally produce escape sequences.
Unicode input
os.read() returns bytes. A UTF-8 character may require multiple bytes, so one byte is not necessarily one character.
Use an incremental decoder from codecs or parse the terminal protocol. Do not decode every individual byte as if the input were ASCII.
Signals and control keys
The ISIG flag allows characters such as Ctrl+C and Ctrl+Z to generate signals. Removing it makes those bytes ordinary input.
Disabling ISIG can prevent users from interrupting the application. Provide a reliable exit key and restore state after exceptions. See Python signal.
Input mappings
Flags including ICRNL, INLCR, and IGNCR control carriage-return and newline transformations. Changing them affects Enter and serial protocols.
Modify only the required bits and preserve the remaining configuration.
Output processing
OPOST enables output processing. Raw configurations may disable it, which can also change newline behavior and cursor positioning.
Interactive applications should normally use the convenience functions in tty or a full terminal library instead of rebuilding every flag manually.
Hardware control flags
cflag contains character size, parity, stop bits, receiver, and hardware-flow-control settings. These are especially relevant for serial ports.
Driver support varies. Incorrect configuration can produce unreadable data, block communication, or disable flow control.
Baud rate
ispeed and ospeed use constants such as B9600 and B115200.
attributes[4] = termios.B115200
attributes[5] = termios.B115200
Not every speed is available. Production serial applications often benefit from a higher-level library such as pyserial.
Wait for output with tcdrain()
tcdrain(fd) waits until queued output has been transmitted. It is useful before changing line parameters or closing a serial device.
The call can block for a long time when hardware is slow or disconnected. Design cancellation and timeouts around the operation.
Discard queues with tcflush()
termios.tcflush(fd, termios.TCIFLUSH)
TCIFLUSH discards input, TCOFLUSH output, and TCIOFLUSH both. Dropping output can lose commands that the application already accepted.
Flow control
tcflow() suspends or resumes input or output with actions such as TCOOFF and TCOON. Do not confuse this software control with hardware flow control.
Send a break
tcsendbreak(fd, duration) sends a break condition on serial lines. A zero duration means roughly 0.25 to 0.5 seconds under POSIX; nonzero meanings are system-dependent.
Window size
Since Python 3.11, tcgetwinsize() returns rows and columns.
rows, columns = termios.tcgetwinsize(sys.stdout.fileno())
print(rows, columns)
tcsetwinsize() sets the associated size when the platform supports it. This is particularly useful for pseudo-terminal tests.
SIGWINCH
Unix processes normally receive SIGWINCH after terminal resize. Let the handler set a flag and recompute layout in the main loop.
The later guide to curses in this batch covers full-screen resize handling.
A reusable context manager
from contextlib import contextmanager
import termios
@contextmanager
def temporary_attributes(fd, modify):
original = termios.tcgetattr(fd)
updated = termios.tcgetattr(fd)
modify(updated)
try:
termios.tcsetattr(fd, termios.TCSADRAIN, updated)
yield
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, original)
Centralizing restoration reduces missed error paths.
Fork and subprocesses
Child processes can inherit the same terminal and see temporary attributes. Avoid starting unrelated subprocesses while the TTY is modified unless that behavior is part of the protocol.
A child can also change the shared TTY state. Use a pseudo-terminal when an interactive program needs isolation.
Threads
The state belongs to the terminal, not a thread. Two threads changing flags can restore values in the wrong order. Keep terminal control in one thread.
Manual recovery
If an experimental program leaves the terminal without echo, the Unix command stty sane usually restores a reasonable state. Document this recovery command for users.
Testing
Test a real terminal and redirected input, Ctrl+C, exceptions during reads, Unicode, arrows, resize, suspend/resume, subprocesses, serial hardware, VMIN/VTIME combinations, and restoration after failure.
Use pty for automated TTY tests, but still perform manual tests on every supported terminal.
Common mistakes
Common failures include omitting finally, modifying the original list, shallow-copying cc, treating one key as one byte, disabling ISIG without another exit path, operating on redirected stdin, changing too many flags, and failing to test exception restoration.
Conclusion
termios provides precise POSIX terminal and serial control. Use it only when low-level flags are necessary; prefer tty, getpass, curses, or specialized serial libraries for common tasks.
Save and restore state, change only required bits, and test on the target Unix system. Consult the official termios documentation and termios(3).







