Terminal Emulators vs. Shells: What Each One Actually Does
'Terminal' and 'shell' get used interchangeably constantly, but they're genuinely separate programs with separate jobs — one draws characters on screen and manages input, the other interprets commands.
“Terminal” and “shell” get used interchangeably in casual conversation constantly — they’re genuinely separate programs with genuinely separate responsibilities, connected through a specific kernel mechanism most users never need to think about directly.
What the terminal emulator actually does
A terminal emulator (Terminal.app, GNOME Terminal, Windows Terminal, iTerm2) is a graphical application responsible for rendering text, handling keyboard input, managing colors and fonts, and interpreting a specific set of escape sequences that control cursor movement, colors, and screen clearing — historically emulating the behavior of physical hardware terminals like the DEC VT100, hence the name.
What the shell actually does
The shell (Bash, Zsh, sh, tcsh) is a completely separate program running inside whatever the terminal emulator provides — it reads the text you type, interprets it as commands, manages variables and control flow, and launches other programs. The shell has no idea how its output is actually being rendered on screen; that’s the terminal emulator’s job entirely.
The kernel mechanism connecting them: the pseudo-terminal
A pseudo-terminal (pty) is the kernel-level construct that actually connects a terminal emulator to a shell — the terminal emulator holds one end (the “master”), the shell holds the other (the “slave”), and the kernel relays data between them. This same pty mechanism is what lets SSH, tmux, and screen all provide “a terminal” to a shell without any physical terminal hardware being involved at all.
Why this separation explains a specific class of “terminal is broken” bugs
stty sane
reset
When binary data accidentally gets sent to a terminal (commonly from running cat on a non-text file), the escape sequences interspersed in that binary data can put the terminal emulator into an unexpected display state — garbled colors, invisible typed text, a corrupted cursor. The shell itself is completely fine in this scenario; it’s the terminal emulator’s interpretation of stray escape sequences that’s broken, which is exactly why reset or stty sane (commands that tell the terminal to restore sane defaults) fix it rather than restarting the shell.
How the terminal tells programs what capabilities it has: terminfo
Terminal emulators vary in exactly which escape sequences they understand — the terminfo database describes a given terminal type’s specific capabilities, and the $TERM environment variable tells programs which terminfo entry to consult. A TUI application queries terminfo rather than hardcoding escape sequences, which is what lets the same program display correctly across genuinely different terminal emulators.
Why remote sessions make this distinction concrete
When you SSH into a remote machine, your local terminal emulator keeps rendering and handling input exactly as before — what changes is which shell, running on which machine, is on the other end of the pty relayed over the network connection. The terminal emulator itself never “moves” anywhere; only the process it’s connected to does.
Why this distinction is worth internalizing
Understanding terminal emulator and shell as two separate, cooperating programs — connected through a pty, each with entirely distinct jobs — is what makes sense of otherwise-confusing scenarios: why a “broken terminal” and a “broken shell” require different fixes, why the same shell behaves identically across different terminal emulators, and why tools like tmux can present a shell session that outlives the specific terminal window that first launched it.