Learning Platform
Глоссарий Troubleshooting
Урок 04.01 · 18 мин
Начальный
TerminalShellttyiTerm2Bash

Terminal vs Shell: что есть что

Открыть «терминал» и «запустить shell» — это два разных действия. Но в обыденной речи их путают: «терминал не работает», «открой bash в терминале», «зайди в shell». Junior должен чётко понимать разницу — это пригодится, когда что-то странное происходит (например, цвета не отображаются, или нажатие стрелки выдаёт ^[[A, а не историю команд).

В этом уроке разберём цепочку: эмулятор терминала -> tty -> shell -> программа. И поймём, как они между собой взаимодействуют.


Истоки: телетайп (teletype, tty)

В 1960-х компьютеры были редкими и дорогими, а пользователей много. Чтобы все могли работать с одним компьютером, к нему подключали электромеханические устройства — телетайпы. Это была печатная машинка с клавиатурой: вы печатаете на клавишах, символы по проводу уходят в компьютер; компьютер шлёт обратно текст — он распечатывается на бумаге.

Сокращение — tty (TeleTYpe). Это сокращение прижилось и живёт до сих пор. Каждый раз, когда вы видите /dev/tty, pts/0, man tty — это исторический след телетайпов 60-х.

История терминала: от железа к эмуляторам
1960-еФизический телетайп Teletype Model 33. Клавиатура + рулон бумаги. Подключался по последовательному порту к мейнфрейму
1970-еVT100 (DEC) — стеклянный терминал с CRT-экраном. ANSI escape codes для цветов и позиционирования курсора. До сих пор стандарт
1980-90-еxterm на X11 — программа-эмулятор. Эмулирует VT100 окошком на экране, общается с unix через pty
2010-еiTerm2 (macOS), GNOME Terminal, Konsole (KDE), tmux. Современные эмуляторы — с табами, разделениями, темами
2020-еAlacritty (GPU-ускоренный), kitty, WezTerm, Warp (AI), Ghostty. Новая волна: производительность + UX

Идея осталась та же, что и в 1960-х: устройство для ввода/вывода текста, подключённое к компьютеру. Только теперь «устройство» — это окно на экране, а «провод» — это виртуальный (pseudo-terminal, pty).


Что такое эмулятор терминала

Эмулятор терминала (terminal emulator) — это программа, которая показывает текст в окне и передаёт клавиатурный ввод дальше. Это GUI-программа, как Chrome или Excel.

Примеры эмуляторов:

Эмуляторы терминала на разных ОС
iTerm2macOS. Открытый код, миллион настроек, splits, профили. Де-факто стандарт на маке
Terminal.appmacOS. Встроенный, по-минимуму. Хуже iTerm2 по фичам, но «есть из коробки»
AlacrittyКросс-платформенный. GPU-ускоренный (использует OpenGL), минималистичный, конфиг в YAML. Очень быстрый
kittyКросс-платформенный. GPU-ускоренный, поддерживает inline-картинки, ligatures. Конкурент Alacritty
GNOME TerminalLinux GNOME. Дефолт на Ubuntu, простой, надёжный
KonsoleLinux KDE. Аналог GNOME Terminal, но с большим количеством настроек
Warp2020+, AI-фичи (autocompletion от LLM), блоки команд, modern UX. Закрытый код, бесплатный
Ghostty2025. Mitchell Hashimoto (HashiCorp). Кросс-платформенный, GPU, нативный UI на каждой ОС
Windows TerminalMicrosoft. Дефолт на современной Windows. Поддерживает PowerShell, cmd, WSL2 bash

Эмулятор НЕ выполняет команды. Он только:

  1. Показывает текст в окне.
  2. Передаёт нажатия клавиш дальше (в shell).
  3. Эмулирует ANSI escape codes (цвета, позиционирование курсора, очистка экрана).

Когда вы открываете эмулятор, он автоматически запускает shell внутри — обычно тот, который указан в настройках или в /etc/passwd. На macOS по умолчанию zsh (с Catalina 2019), на Linux — обычно bash.


Что такое shell

Shell — это программа-интерпретатор, которая читает команды и выполняет их. На каждое нажатие Enter shell делает: разбирает строку, ищет команду по $PATH, fork+exec, ждёт завершения, показывает prompt снова.

Это абсолютно отдельная программа от эмулятора. Эмулятор может работать без shell (внутри запустится что угодно). Shell может работать без эмулятора (например, в скрипте, в SSH-сессии, в systemd-сервисе).

fork() и exec() — как ядро запускает процесс
Связь terminal emulator ↔ shell
Terminal EmulatorGUI программа: iTerm2, GNOME Terminal. Показывает текст, ловит клавиши
запускает + pty
Shell (bash / zsh / fish)Программа-интерпретатор. Читает из stdin, пишет в stdout/stderr. Обычно её stdin/stdout соединены с pty
fork + exec
ls / python / git ...Запущенная программа. Тоже читает stdin / пишет stdout. Через pty всё это идёт обратно в эмулятор

Цепочка такая: эмулятор создаёт pty (pseudo-terminal pair), запускает shell, подключает его stdin/stdout/stderr к pty. Когда вы вводите команду в окне эмулятора, символы идут через pty в shell. Когда shell пишет вывод — он идёт через pty обратно и эмулятор рисует это в окне.


/dev/tty и pts/N

Откройте терминал и выполните tty:

$ tty
/dev/pts/0

Это говорит: ваш shell привязан к pseudo-terminal slave с номером 0. На Linux pseudo-terminals живут в /dev/pts/. Откройте ещё один терминал — там будет /dev/pts/1. Третий — pts/2. И так далее.

На macOS пути немного отличаются: /dev/ttys000, /dev/ttys001 и так далее. Идея та же.

/dev/tty — это специальный «магический» путь, который всегда указывает на текущий терминал процесса:

$ echo "Hello" > /dev/tty
Hello
$ cat /dev/tty   # читает с клавиатуры
type something  
type something  

Это полезно, когда программа хочет общаться с пользователем напрямую, в обход stdin/stdout (например, при чтении пароля).

TIP

В скрипте может быть полезно знать, запущен ли он в терминале или в pipe. Проверка: [[ -t 0 ]] — если stdin привязан к терминалу. Это позволит скрипту вести себя по-разному: интерактивно или нет.


Какие есть shell-ы

На современных системах живут несколько shell-ов. Каждый — своя программа, со своим синтаксисом, своим набором фич.

Главные shell-ы в 2026
sh (dash)POSIX-совместимый минимальный shell. /bin/sh на Debian/Ubuntu — это dash (быстрый, маленький). Главное применение — системные скрипты
bashBourne Again SHell. GNU. POSIX-совместимый + куча extensions. Дефолт на большинстве Linux, на macOS до 2019
zshZ Shell. Совместим с bash на 95%. Лучше completion, мощнее prompt. Дефолт на macOS с Catalina (2019). Базис oh-my-zsh
fishFriendly Interactive SHell. НЕ POSIX. Свой синтаксис, не совместим с bash скриптами. Очень удобен для интерактива
nushellНовый shell на Rust. Работает со структурированными данными (типы, таблицы). Эксперимент. Не POSIX
kshKorn Shell. Старый, на RHEL ещё встречается. На современных систем — почти не используется

В чём практическая разница? Чтобы понять, посмотрим, как один и тот же скрипт ведёт себя в разных shell:

# bash / zsh / sh — POSIX-совместимый синтаксис
for i in 1 2 3; do
  echo "Number: $i"
done

# fish — другой синтаксис
for i in 1 2 3
  echo "Number: $i"
end

# nushell — ещё другой
for i in [1 2 3] {
  echo $"Number: ($i)"
}

Bash и zsh имеют общий синтаксис скриптов (с минимальными различиями). Fish и nushell — несовместимы.

Какой shell у вас сейчас:

$ echo $SHELL
/bin/bash

$ readlink /proc/$$/exe    # Linux: реальный путь к процессу shell
/usr/bin/bash

$SHELL — это переменная окружения, которая хранит «предпочитаемый shell пользователя» (из /etc/passwd). Это не всегда тот shell, в котором вы СЕЙЧАС находитесь — если вы запустили zsh из bash, в этом zsh переменная $SHELL всё ещё будет показывать /bin/bash.


macOS vs Linux: дефолтный shell

Историческая нота. До macOS Catalina (2019) дефолтным shell был bash. Apple перешла на zsh из-за лицензии: bash перешёл на GPLv3, а Apple GPLv3 -несовместимы (по корпоративным юридическим причинам). zsh с лицензией MIT — никаких проблем.

На Linux дефолт — bash почти везде, за исключением Alpine (там ash из busybox) и некоторых других минимальных дистрибутивов.

Что это значит на практике:

  • На Mac: bash ещё есть, но это старый bash 3.2 (последний GPLv2). Чтобы получить bash 5.3 — brew install bash.
  • На Ubuntu/Debian: bash 5.3 из коробки в новых релизах (26.04 / Trixie). На старых — bash 5.0+ — тоже хорошо.
  • В Docker-образах Alpine: НЕТ bash по умолчанию, только ash. Если делаете RUN bash script.sh — упадёт. Решение: apk add bash в Dockerfile, или писать на чистом POSIX sh.
# Узнать версию bash
$ bash --version
GNU bash, version 5.3.0(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2025 Free Software Foundation, Inc.

# На macOS встроенный — старый
$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin22)

Старый bash 3.2 на macOS отсутствуют важные фичи (ассоц-массивы, &>, и многое другое из bash 4.0+). Поэтому на Mac для bash-скриптов обычно ставят свежий bash через Homebrew и shebang делают #!/usr/bin/env bash (берёт из PATH, не системный /bin/bash).


WSL2 на Windows

Windows Subsystem for Linux 2 — это полноценное Linux-ядро, работающее на Windows через Hyper-V. На WSL2 можно поставить Ubuntu, Debian, Alpine — почти любой дистрибутив. Поверх — bash, как обычно.

Для DE на Windows-машине это лучший вариант. Не виртуалка с лагающим GUI, не curio cygwin — настоящий Linux под капотом. Файлы из Windows доступны через /mnt/c/Users/..., файлы из Linux — через \\wsl.localhost\Ubuntu\home\user\....

# В PowerShell на Windows
PS> wsl --install -d Ubuntu
PS> wsl
user@host:~$ uname -a
Linux host 6.6.0-microsoft-standard-WSL2 #1 SMP ...

После этого внутри WSL — обычный Linux, можно следовать любым Ubuntu-инструкциям.


Цепочка целиком

Когда вы открываете терминал и пишете команду, происходит следующее:

Полная цепочка при выполнении команды
iTerm2Получает нажатие клавиши 'l', потом 's', потом Enter
через pty
bashЧитает строку из stdin, парсит 'ls', ищет в PATH, делает fork+exec
lsДочерний процесс bash. Делает getdents(), пишет результат в stdout (fd 1)
stdout
через ptyBytes идут обратно через pty в эмулятор
iTerm2 рисуетПарсит ANSI escape codes, рисует текст и цвета в окне

Это много шагов, но всё работает на скорости миллисекунд. Для пользователя выглядит как «нажал Enter — увидел вывод».

Когда что-то идёт не так:

  • Стрелки выводят ^[[A — эмулятор не правильно эмулирует, или shell не понимает ANSI escape codes для стрелок (старый dash, например).
  • Цвета не работаютTERM переменная не та (echo $TERM должен показать xterm-256color или похожее).
  • Размер экрана 80x24, а окно больше — терминал не передал ему обновление размера (stty -a покажет текущий размер).

Попробуй сам

Откройте 2-3 терминала и посмотрите, что у вас:

$ tty
/dev/pts/0     # или /dev/ttys000 на Mac

$ echo $SHELL
/bin/bash      # или /bin/zsh на Mac

$ ps -p $$     # показать инфу о текущем процессе shell
   PID TTY          TIME CMD
 12345 pts/0    00:00:00 bash

$ echo $TERM
xterm-256color  # на современных эмуляторах

$$ — это специальная bash-переменная: PID текущего shell. ps -p $$ показывает информацию о нём самом.

Запустите вложенный shell:

$ bash           # запустили bash внутри bash
$ ps -p $$
   PID TTY          TIME CMD
 12346 pts/0    00:00:00 bash
$ exit           # вышли из вложенного
$ ps -p $$
   PID TTY          TIME CMD
 12345 pts/0    00:00:00 bash

Видите: вложенный shell имеет свой PID, и Ctrl+D / exit возвращает в родительский.


Проверка знанийKnowledge check
Junior жалуется: «Я нажимаю стрелку вверх, но вместо предыдущей команды выводится ^[[A». Что произошло, и где искать причину?
ОтветAnswer
Это значит, что эмулятор терминала корректно отправляет ANSI escape sequence для стрелки (\x1b[A = ESC + [ + A), но shell, в котором вы находитесь, не интерпретирует её как «история вверх». Обычно это происходит в трёх случаях: (1) Вы запустили dash или другой minimal POSIX shell, у которого нет встроенной поддержки readline (история, line editing). (2) Вы в bash, но без readline (редкий случай — статически собранный bash или Docker-минималка). (3) Вы внутри программы, которая считывает stdin построчно без обработки клавиш (например, при cat или Python REPL без readline). Решение зависит от ситуации: установить bash вместо dash, поставить readline-библиотеку, или использовать rlwrap (обёртка, добавляющая readline-функциональность любой программе). В Docker-Alpine очень частая ситуация — там по умолчанию ash; решается apk add bash && bash.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Чем отличается terminal emulator от shell?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4