Тема 01

Linux, терминал и командная оболочка

Linux, терминал и командная оболочка

Курс начинается с вопроса, который для большинства читателей звучит непривычно: зачем открывать окно с мигающим курсором и печатать команды, если почти всё можно сделать мышью. Ответ складывается из трёх соображений. Команду можно записать, повторить и поместить в файл-скрипт, и тогда завтрашний запуск выполнит ту же работу, что и сегодняшний. Команды работают на сервере без экрана и графического интерфейса, и именно через них администрируются большинство серверов, в том числе учебный сервер из курса «Компьютерные сети». Наконец, маленькие программы можно соединять в цепочки, передавая результат одной в качестве входа другой. Все три свойства заложены не сегодня, а в системе UNIX, созданной в конце 1960-х годов.

Тема решает три задачи. Первая — разобраться в понятиях, которые в обиходе смешиваются: операционная система, ядро, дистрибутив, терминал, эмулятор терминала, консоль и командная оболочка. Вторая — получить работающую систему Linux через подсистему WSL2 или виртуальную машину и понять, чем такая установка отличается от «настоящего» Linux. Третья — освоить синтаксис команды, средства справки и редактирования строки, без которых самостоятельная работа в терминале невозможна. Файловая система и навигация по каталогам рассматриваются в теме 2, настройка оболочки — в теме 8.

Изложение начинается с операционной системы и её истории, затем вводятся терминал и оболочка, описывается установка WSL2, после чего разбирается синтаксис команды, справка и история команд. Примеры выполнены в оболочке bash в дистрибутиве Ubuntu 22.04 под WSL2; вывод приведён без изменений, если не считать имени пользователя, которое заменено на student. Там, где команда требует прав администратора или работы в Windows, это оговорено в тексте.

Операционная система и ядро

Что делает операционная система

Операционная система (англ. operating system) — набор программ, который управляет аппаратурой и предоставляет остальным программам общие службы: распределение процессора и памяти, доступ к дискам и сети, единые правила запуска программ и разграничение доступа пользователей к данным 1. Текстовый редактор или браузер не обращается к диску напрямую: он обращается к системе, а система решает, разрешено ли это и в каком порядке выполнить. Без такого посредника несколько одновременно работающих программ испортили бы данные друг другу, и именно поэтому многопользовательские системы появились раньше персональных компьютеров.

Операционная система состоит из двух частей, которые полезно различать. Ядро (англ. kernel) работает в привилегированном режиме процессора, имеет полный доступ к оборудованию и отвечает за планирование процессов, управление памятью, файловые системы, драйверы устройств и сетевой стек. Всё остальное относится к пользовательскому пространству (англ. user space): командная оболочка, утилиты вроде ls и cp, серверы, графические приложения. Программы пользовательского пространства обращаются к ядру через системные вызовы (англ. system calls). Так, команда cat, которая выводит содержимое файла, сама не читает диск: она просит ядро открыть файл системным вызовом open и прочитать его вызовом read, а ядро при этом проверяет права.

Граница между этими частями имеет практическое значение. Программа, которая зависла в пользовательском пространстве, может быть завершена, и система продолжит работу. Ошибка в ядре затрагивает всю систему сразу. Права доступа, которые изучаются в теме 4, проверяет именно ядро, поэтому обойти их из обычной программы нельзя.

Ядро Linux и дистрибутивы

Linux — это ядро, а не полная операционная система. Программы, которые делают систему пригодной к работе, — оболочка, утилиты для работы с файлами и текстом, библиотека языка C, менеджер пакетов, система инициализации — в основном созданы в рамках проекта GNU. Поэтому точнее говорить о системах GNU/Linux. Дистрибутив (англ. distribution) — это готовый набор, в котором ядро, системные программы, установщик и менеджер пакетов собраны и настроены вместе. Debian, Ubuntu, Fedora и Arch Linux различаются составом пакетов, сроками обновлений, политикой поддержки и умолчаниями, но ядро и большинство команд у них общие.

Курс опирается на Ubuntu. Выпуски с долгосрочной поддержкой (англ. Long Term Support, LTS) выходят раз в два года и поддерживаются несколько лет; Ubuntu 24.04 LTS вышла 25 апреля 2024 года. Ubuntu основана на Debian и использует тот же менеджер пакетов APT, который рассматривается в теме 9. Для лабораторных работ курса основным вариантом выбрана именно версия 24.04, однако примеры вывода в этой теме получены в версии 22.04, и в отдельных строках (версия ядра, дата сборки) вывод на другой версии будет отличаться.

Архитектурные модели: монолитное ядро Linux против гибридного ядра Windows NT

Для глубокого понимания принципов работы операционных систем полезно сопоставить архитектуру ядра Linux с архитектурой семейства Windows NT, разработанной Дэвидом Катлером 9:

  1. Организация пространства ядра:
    • Linux — монолитное ядро (Monolithic Kernel): планировщик задач, виртуальная память, сетевой стек, подсистема VFS и драйверы устройств выполняются в едином привилегированном адресном пространстве (Ring 0). Взаимодействие между модулями происходит через прямые вызовы функций на скорости процессора без накладных расходов на переключение контекста. Динамическое расширение функциональности ядра без перезагрузки обеспечивается загружаемыми модулями ядра (англ. Loadable Kernel Modules, LKM).
    • Windows NT — гибридное ядро (Hybrid Kernel): сочетает черты микроядра и монолита. Аппаратная платформа изолируется уровнем абстракции оборудования (Hardware Abstraction Layer, HAL). Базовые примитивы синхронизации и диспетчеризация прерываний возложены на микроядро, а службы управления памятью, объектами и безопасностью сгруппированы в исполнительную систему (NT Executive). Пользовательские приложения взаимодействуют с ядром через подсистемы окружения (Win32, подсистема WSL).
  2. Управление конфигурацией системы:
    • Философия Linux: «всё есть текст». Конфигурация системы децентрализована и хранится в человекочитаемых текстовых файлах каталога /etc. Это позволяет редактировать настройки любым текстовым редактором, автоматизировать администрирование скриптами Bash и отслеживать историю изменений системы в репозиториях Git. Внутреннее состояние ядра проецируется в псевдофайловые системы /proc и /sys.
    • Философия Windows: централизованный реестр (Windows Registry) — иерархическая двоичная база данных настроек (кусты HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER), доступная через системные API ядра или специализированные утилиты (regedit, PowerShell).
  3. Модель порождения процессов:
    • В стандарте POSIX и Linux процесс порождается разделением: системный вызов fork() дублирует адресное пространство родителя с механизмом оптимистического копирования при записи (Copy-on-Write, COW), после чего системный вызов execve() загружает в адресное пространство новую программу.
    • В Windows процесс создаётся единым вызовом CreateProcess(), который атомарно конструирует объект процесса, выделяет память, настраивает дескрипторы безопасности (Security Descriptors) и запускает первичный поток.

Сравнительная схема архитектурных уровней и пространств памяти приведена на рисунке ниже.

Архитектура монолитного ядра Linux и гибридного ядра Windows NT
Сравнение архитектурных уровней Linux и Windows NT: Ring 0, Ring 3 и системные подсистемы

История UNIX и Linux

UNIX в Bell Labs

История UNIX начинается в 1969 году в исследовательском центре Bell Labs компании AT&T. Кен Томпсон (Ken Thompson) и Деннис Ритчи (Dennis Ritchie) с коллегами начали разработку небольшой операционной системы после того, как их участие в громоздком проекте Multics было прекращено. Название UNIX представляет собой игру слов с Multics. Первые версии писались на ассемблере для миникомпьютера PDP-7, затем для PDP-11. В 1973 году четвёртая версия была переписана на языке C, что сделало систему переносимой: ядро, написанное на высокоуровневом языке, можно адаптировать к другой машине, переписав небольшую её часть 2.

Первое внутреннее руководство по системе датируется ноябрём 1971 года, а внешний выпуск состоялся в октябре 1973 года. В 1970-х годах система лицензировалась университетам вместе с исходными текстами, поэтому UNIX стала основой обучения системному программированию во многих вузах. Ритчи и Томпсон описали систему в статье «The UNIX Time-Sharing System», опубликованной в журнале Communications of the ACM в 1974 году 2.

Оболочка появилась вместе с системой. Первая оболочка UNIX, написанная Томпсоном, поставлялась с версиями 1–6 в 1971–1975 годах. Оболочка Bourne shell, созданная Стивеном Борном (Stephen Bourne) и поставлявшаяся с седьмой версией UNIX в 1979 году, ввела механизмы, которые используются до сих пор: здесь-документы, подстановку команд и более общие переменные 3. Bash, которой посвящён курс, — совместимое с Bourne shell расширение, о чём сказано в одном из следующих разделов.

Семейство систем и стандарты

К середине 1980-х годов UNIX разделилась на несколько ветвей. Ветвь System V развивалась в AT&T и её наследниках, ветвь BSD — в Калифорнийском университете в Беркли. Программы, написанные для одной версии, часто не работали на другой, и это стало серьёзной проблемой для пользователей и производителей. Ответом стал стандарт POSIX (англ. Portable Operating System Interface): в 1988 году был опубликован первый стандарт IEEE 1003.1, описывавший системный интерфейс, то есть набор системных вызовов и библиотечных функций 4. Программы, написанные по стандарту, переносятся между системами без переписывания, а основные возможности таких команд, как ls или grep, совпадают.

Стандарт не отменяет различий. Многие утилиты имеют расширения, которых нет в POSIX, и в редких случаях поведение зависит от реализации. Эти различия приходится учитывать при написании скриптов (тема 15). Читая справку, важно понимать, описывает ли страница общее поведение или расширение конкретной программы.

Проект GNU и Linux

Ричард Столлман (Richard Stallman) 27 сентября 1983 года объявил о начале проекта GNU, цель которого — создать свободную операционную систему, совместимую с UNIX и предоставляющую пользователям право запускать, изучать, изменять и распространять программы 4. К началу 1990-х годов проект располагал почти всеми системными программами — компилятором, оболочкой, утилитами, библиотекой C, — но не имел работоспособного ядра. Оболочка bash создана в рамках этого проекта Брайаном Фоксом (Brian Fox) в 1989 году.

25 августа 1991 года Линус Торвальдс (Linus Torvalds), студент Хельсинкского университета, опубликовал в группе новостей comp.os.minix сообщение о том, что он создаёт свободную операционную систему для процессоров семейства Intel 386 как личный проект. 17 сентября 1991 года вышла версия 0.01 ядра. Ядро Linux быстро стало тем ядром, с которым работали утилиты GNU, поэтому системы, которые сегодня называют Linux, на самом деле представляют собой сочетание ядра Linux и программ GNU 4.

Важнее понимать устройство, чем запоминать даты. UNIX дала модель системы и набор программ, стандарт POSIX сделал их переносимыми, GNU предоставила свободную реализацию, а Linux — ядро, которое работает на обычных компьютерах. Большинство команд, рассматриваемых в курсе, одинаковы во всех этих системах.

Ключевые даты истории UNIX и Linux
От создания UNIX в Bell Labs до стандарта POSIX, проекта GNU и появления ядра Linux

Философия UNIX

Система UNIX создавалась небольшой командой и отражала несколько инженерных принципов, которые Кернигэн и Пайк изложили в книге 1984 года 5, а Эрик Реймонд позднее систематизировал 6. Первый принцип — модульность: программа делает одну вещь и делает её хорошо. Программа wc считает строки, слова и байты, sort сортирует, uniq убирает повторяющиеся строки. Второй — текст как универсальный интерфейс: вход и выход программ представляют собой текстовые потоки, которые может прочитать человек и обработать другая программа. Третий — композиция: программы соединяются конвейерами, и результат сложной задачи возникает из цепочки простых шагов. Четвёртый — предпочтение простоты: простое решение, которое работает в большинстве случаев, обычно лучше сложного, которое покрывает всё.

Эти принципы определяют и то, как выглядит работа в терминале. Командная строка — не «старый интерфейс», а язык, в котором короткие команды сочетаются так же, как слова в предложении. Пример конвейера приводится в теме 5, обработка текста — в теме 6.

Терминал, эмулятор, консоль и оболочка

Четыре понятия

Слова «терминал», «консоль» и «командная строка» употребляются в разговорной речи как синонимы, хотя обозначают разные вещи. Различие важно, потому что при сбое нужно понимать, какая из частей работает неверно: окно не открывается, символы отображаются неправильно или команда не находится. Таблица 1 описывает четыре понятия.

Таблица 1. Понятия, связанные с работой в терминале

ПонятиеЧто этоПример
Терминал (англ. terminal)исторически — устройство из клавиатуры и экрана, подключённое к компьютеру; в современных системах — абстракция для обмена символами с программойвидеотерминал VT100 (1978) и его потомки
Эмулятор терминала (англ. terminal emulator)программа, которая в окне графической среды имитирует видеотерминал: показывает символы и передаёт нажатия клавишWindows Terminal, GNOME Terminal, окно Ubuntu в WSL
Консоль (англ. console)системный терминал, подключённый к ядру напрямую, без графической среды; в Linux это виртуальные консоли tty1–tty6экран, на котором Linux показывает приглашение входа без графической оболочки
Командная оболочка (англ. shell)программа, которая читает строку, разбирает её, находит команду, запускает её и выводит результатbash, sh, zsh, dash

Из таблицы видно, что эмулятор и оболочка — разные программы. Эмулятор отвечает за окно, шрифт, прокрутку и цвета, оболочка — за смысл введённой строки. Можно сменить эмулятор, сохранив bash, и сменить оболочку, сохранив окно. Консоль отличается от эмулятора тем, что это не программа в окне, а сам терминал системы.

Цепочку, связывающую нажатие клавиши с результатом, удобно показать схемой. Пользователь нажимает клавиши, эмулятор передаёт их через псевдотерминал оболочке, оболочка разбирает строку и запускает программу, программа обращается к ядру, а результат возвращается тем же путём.

Схема: пользователь, эмулятор терминала, оболочка, программа, ядро
Рисунок 1. Путь команды от клавиатуры до ядра и обратно

Рисунок 1 показывает и то, почему программа ls не знает ни о каком окне: она получает вход и пишет результат в стандартные потоки, которые подключает оболочка. Стандартные потоки подробно рассматриваются в теме 5.

Оболочки: bash, sh, zsh и dash

Оболочка — обычная программа, и в системе может быть установлено несколько оболочек. Файл /etc/shells перечисляет те из них, которые система считает допустимыми для входа пользователя:

cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/sh
/bin/dash

Оболочка, которая запускается при входе, записана в переменной окружения SHELL, а текущая оболочка определяется по имени её процесса. Проверим оба значения.

echo $SHELL
ps -p $$ -o comm=
/bin/bash
bash

Переменная SHELL указывает, какую оболочку запускать для пользователя, а $$ — идентификатор текущего процесса оболочки. Команда ps -p $$ -o comm= выводит имя программы для этого процесса. О процессах подробно говорится в теме 7, о переменных окружения — в теме 8.

Основные оболочки различаются так. Bash (англ. Bourne-Again SHell, «снова Bourne-оболочка») — основная оболочка GNU/Linux и популярный вариант для скриптов; именно её изучаем в курсе 3. Sh — имя стандартной оболочки POSIX; в Ubuntu /bin/sh указывает на dash — лёгкую реализацию, которая быстро запускается и используется для системных скриптов. Zsh — расширенная оболочка с развитым автодополнением, которая по умолчанию установлена в macOS, начиная с версии Catalina. Все они понимают общий базовый синтаксис, но в деталях различаются, и скрипт, написанный для bash, может не работать в dash. Этот вопрос вернётся в теме 15.

Проверим, на какую программу указывает /bin/sh:

ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan  7  2025 /bin/sh -> dash

Первый символ строки l означает символическую ссылку, а стрелка показывает, куда она ведёт. Формат вывода ls -l разбирается в теме 2.

Установка Linux: WSL2 и виртуальная машина

Варианты для начинающего

Есть три пути получить работающий Linux. Первый — установить Linux вместо Windows или рядом с ней (двойная загрузка): это полноценная система, но установка требует разметки диска и аккуратности. Второй — виртуальная машина (VirtualBox, VMware, Hyper-V): Linux работает внутри окна на виртуальном оборудовании, и её легко удалить. Третий — подсистема WSL2 (англ. Windows Subsystem for Linux), которая устанавливает дистрибутив Linux в Windows одной командой. Курс рекомендует WSL2 или виртуальную машину; установка Linux вместо Windows требует опыта и в обязательную часть работы не входит.

Что такое WSL2

Подсистема WSL существует в двух версиях. Первая переводила системные вызовы Linux в вызовы ядра Windows и поэтому не была полноценным Linux. Вторая версия (WSL 2), анонсированная в мае 2019 года, запускает настоящее ядро Linux внутри легковесной виртуальной машины, которую обслуживает гипервизор Hyper-V. Файлы дистрибутива хранятся в виртуальном жёстком диске, а файлы Windows доступны внутри Linux через каталог /mnt/c 7. В курсе используется WSL 2, и именно эта версия выбирается по умолчанию при установке.

WSL2 не является эмулятором и не является контейнером в обычном понимании. Программы Linux выполняются на процессоре компьютера, ядро настоящее, пакеты устанавливаются из репозиториев дистрибутива. Граница между Windows и Linux при этом сохраняется: окно терминала открывает Windows, файлы находятся в разных местах, сеть общая, но у дистрибутива собственный адрес.

Установка по документации Microsoft

Документация Microsoft описывает установку одной командой. Для неё нужна Windows 10 версии 2004 (сборка 19041) или более новая либо Windows 11 7. Порядок действий такой: открыть PowerShell от имени администратора, выполнить команду установки, перезагрузить компьютер и запустить установленный дистрибутив, который попросит задать имя пользователя и пароль Linux.

# в PowerShell с правами администратора
wsl --install
# после перезагрузки
wsl --install -d Ubuntu-24.04

Команда wsl --install без параметров устанавливает подсистему и дистрибутив Ubuntu по умолчанию. Если подсистема уже установлена, команда выводит справку; в этом случае список доступных дистрибутивов показывает wsl --list --online, а установить конкретный можно командой wsl --install -d с именем из этого списка. Имя Ubuntu-24.04 приведено как пример: точное название берётся из списка на конкретной версии Windows. Вывод команд, выполняемых в Windows, в тексте не приводится, так как он зависит от версии системы и в среде подготовки материала не получен.

Проверить внутри дистрибутива, что установлен нужный выпуск и что ядро действительно Linux, можно двумя командами. Символ | передаёт вывод одной команды на вход другой; подробно это рассматривается в теме 5.

cat /etc/os-release | head -n 2
cat /proc/version
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
Linux version 6.6.87.2-microsoft-standard-WSL2 (root@439a258ad544) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils) 2.37) #1 SMP PREEMPT_DYNAMIC Thu Jun  5 18:30:46 UTC 2025

Строка microsoft-standard-WSL2 в версии ядра указывает на WSL 2. В Ubuntu 24.04 на той же схеме строки будут иными, но структура вывода сохранится.

Отличия WSL2 от «настоящего» Linux

Несколько отличий стоит знать заранее. Во-первых, файлы Windows видны в /mnt/c, но работа с ними через этот путь заметно медленнее, чем с файлами внутри дистрибутива, поэтому учебные проекты лучше держать в домашнем каталоге Linux (~); подробнее в теме 2. Во-вторых, в старых версиях WSL служба systemd не запускалась, и управлять сервисами было нельзя; её включение через файл /etc/wsl.conf описано в теме 9. В-третьих, ядро поставляется Microsoft и обновляется через механизм обновления WSL, а не через менеджер пакетов Ubuntu. Наконец, сеть в WSL2 имеет собственный IP-адрес, поэтому обращение к службам внутри дистрибутива из Windows может требовать отдельной проверки; это рассматривается в теме 11.

Синтаксис команды, опции и аргументы

Из чего состоит команда

Команда, введённая в приглашении, — строка текста, которую оболочка разбирает на слова, разделённые пробелами. Первое слово — имя команды. Остальные слова — параметры команды. Они бывают двух видов: опции (англ. options), которые изменяют поведение программы и обычно начинаются с дефиса, и аргументы (англ. arguments) — объекты, над которыми программа работает: файлы, имена, строки. Общая форма записывается так:

команда [опции] [аргументы]

Квадратные скобки здесь обозначают необязательные части; в самой команде их не пишут. Такое соглашение описано в справочных страницах и используется во всех системах Linux 8.

Рисунок 2 разбирает команду по частям.

Разбор команды grep с опциями и аргументами
Рисунок 2. Части команды: имя, короткая опция, длинная опция, аргументы

Пример выбран условно: grep — программа поиска по тексту, которую подробно изучим в теме 6. Здесь важно заметить, что в большинстве программ опции стоят перед аргументами, а смысл каждого слова определяет сама программа. Оболочка слова не интерпретирует, кроме кавычек и подстановок, о которых будет сказано ниже.

Пример с программой uname, которая выводит сведения о системе:

uname
uname -s
uname -s -r
uname -sr
Linux
Linux
Linux 6.6.87.2-microsoft-standard-WSL2
Linux 6.6.87.2-microsoft-standard-WSL2

Без опций uname выводит только имя ядра. Опция -s выводит это имя явно, -r добавляет версию ядра. Последние две команды дают одинаковый результат: две короткие опции с отдельными дефисами и опции, записанные слитно, понимаются одинаково.

Короткие и длинные опции

Короткая опция состоит из одного дефиса и одной буквы. Несколько коротких опций можно записать слитно. Длинная опция начинается с двух дефисов и содержит слово. Длинная форма тех же опций выглядит так:

uname --kernel-name --kernel-release
Linux 6.6.87.2-microsoft-standard-WSL2

Длинные опции понятнее в скриптах и при чтении чужих команд, короткие быстрее набирать в интерактивной работе. Некоторые опции принимают значение, которое пишется через знак равенства, например --color=auto, или отдельным словом после короткой опции. Какие опции существуют, показывают раздел OPTIONS справочной страницы и вывод --help; об этом подробно в разделе о справке ниже.

Кавычки и разбиение на слова

Оболочка делит строку по пробелам. Если аргумент содержит пробел, его нужно заключить в кавычки, иначе одна строка превратится в несколько аргументов. Пример:

echo "a   b"
echo a   b
echo 'a   b'
a   b
a b
a   b

Программа echo выводит свои аргументы через один пробел. В первой и третьей командах кавычки сохранили все пробелы, во второй оболочка передала echo два слова a и b, а пробелы между ними свернула. Двойные и одинарные кавычки различаются тем, что двойные разрешают подстановку переменных, одинарные — нет:

echo '$USER'
echo "$USER"
$USER
student

Тот же эффект виден при создании каталогов с пробелом в имени. Команда mkdir my dir создаёт два каталога, а не один:

mkdir my dir
ls -F
dir/
my/

Опция -F программы ls добавляет к именам каталогов символ /. Чтобы создать один каталог с пробелом, нужны кавычки: mkdir "my dir". Подробно о кавычках и подстановках сказано в теме 13; для первого знакомства достаточно правила: аргумент с пробелом или специальным символом заключается в кавычки.

Коды возврата и сообщения об ошибках

Каждая команда по завершении возвращает код возврата (англ. exit status): число от 0 до 255. Ноль означает успех, любое другое значение — ошибку. Код последней команды хранится в специальной переменной $?. Проверим это на команде с ошибкой имени:

lss -l
echo "код возврата: $?"
bash: lss: command not found
код возврата: 127

Сообщение command not found и код 127 означают, что оболочка не нашла команду ни среди своих встроенных, ни среди файлов в каталогах PATH. Чаще всего это опечатка, как здесь. Другие типичные сообщения:

ls --sizee
ls -z
ls -la /nonexistent_dir
cat /etc/shadow
ls: unrecognized option '--sizee'
Try 'ls --help' for more information.
ls: invalid option -- 'z'
Try 'ls --help' for more information.
ls: cannot access '/nonexistent_dir': No such file or directory
cat: /etc/shadow: Permission denied

Сообщения имеют единую структуру: имя программы, двоеточие, описание проблемы и объект, с которым она связана. Их смысл таков:

  • unrecognized option и invalid option — программа не знает такой опции. Причина почти всегда опечатка в опции; подсказка Try 'ls --help' предлагает сверить опции со справкой. Короткая опция из одной буквы выводится в сообщении как invalid option -- 'z', длинная — как unrecognized option '--sizee'.
  • No such file or directory — путь или имя файла не существует. Причина — опечатка в имени или неверный каталог. Программа ls в этом случае завершается с кодом 2 («серьёзная ошибка»), тогда как код 127 выставляет сама оболочка, не нашедшая команду.
  • Permission denied — файл существует, но у пользователя нет прав. Механизм прав рассматривается в теме 4; пока достаточно заметить, что файл /etc/shadow доступен только администратору.

Сообщения об ошибках выводятся в отдельный поток (стандартный поток ошибок), поэтому их можно отделить от обычного результата. Это также рассматривается в теме 5.

Как оболочка находит команду

Имя команды может обозначать разные вещи. Это может быть встроенная команда (англ. builtin), которая выполняется самой оболочкой, или внешняя программа — отдельный файл, найденный в каталогах переменной PATH. Команда type показывает, что именно скрывается за именем:

type cd
type ls
type echo
cd is a shell builtin
ls is /usr/bin/ls
echo is a shell builtin

Команда cd — встроенная, ls — внешняя программа в /usr/bin, а echo встроена в оболочку, хотя существует и одноимённая программа. Чтобы увидеть все варианты, используются опции -t (короткий тип) и -a (все места):

type -t cd
type -t ls
type -a echo
builtin
file
echo is a shell builtin
echo is /usr/bin/echo
echo is /bin/echo

Опция -t выводит тип одним словом: builtin, file, function, alias, keyword. Опция -a перечисляет все найденные варианты, в порядке, в котором оболочка их ищет. Порядок показан на рисунке 3.

Порядок поиска команды: псевдоним, ключевое слово, функция, встроенная команда, файл в PATH
Рисунок 3. Порядок поиска имени команды в bash

По руководству bash поиск устроен так: сначала проверяются псевдонимы, ключевые слова и функции, затем встроенные команды; если имя не найдено, оболочка перебирает каталоги из PATH и ищет исполняемый файл с таким именем 3. Поэтому встроенная команда перекрывает одноимённую программу. Переменная PATH и её настройка рассматриваются в теме 8.

Утилита which ищет только файлы в каталогах PATH, не зная о встроенных командах:

which ls
which cd
echo "код возврата: $?"
/usr/bin/ls
код возврата: 1

Для cd which ничего не выводит и завершается с кодом 1, потому что cd — встроенная команда и файла не имеет. Команда command -v объединяет обе проверки: она выводит имя для встроенных команд и путь для внешних. Для изучения команд удобнее использовать type.

Почему cd встроена, а не является программой? Внешняя программа запускается в отдельном процессе, и её рабочий каталог принадлежит этому процессу. Когда программа завершается, родительская оболочка сохраняет свой каталог без изменений. Чтобы сменить каталог самой оболочки, команда должна выполняться внутри неё. Аналогично устроены export, alias и history. Механизм наследования окружения описан в теме 8.

Справка, история команд и редактирование строки

Справочные страницы man

Команда man открывает справочную страницу (англ. manual page). Страницы разбиты на разделы, и одно имя может иметь описания в нескольких разделах. Поэтому whatis показывает все варианты:

whatis passwd
whatis printf
passwd (1)           - change user password
passwd (1ssl)        - OpenSSL application commands
passwd (5)           - the password file
printf (3)           - formatted output conversion
printf (1)           - format and print data

Здесь passwd (1) — команда смены пароля, а passwd (5) — описание файла /etc/passwd. Номер раздела можно указать явно, и тогда man ищет страницу только в нём:

man 5 passwd | sed -n 1,12p
PASSWD(5)                File Formats and Conversions                PASSWD(5)

NAME
       passwd - the password file

DESCRIPTION
       /etc/passwd contains one line for each user account, with seven fields
       delimited by colons (“:”). These fields are:

       •   login name

       •   optional encrypted password

Заголовок PASSWD(5) сообщает имя и раздел; раздел File Formats and Conversions — это описание формата файла. Вызов sed -n 1,12p выводит первые двенадцать строк, а sed подробно рассматривается в теме 6. Таблица 2 описывает разделы системы.

Таблица 2. Разделы справочных страниц Linux

РазделСодержаниеПример
1исполняемые программы и команды оболочкиman 1 ls
2системные вызовы (функции ядра)man 2 open
3функции библиотек, в том числе стандартной библиотеки Cman 3 printf
4специальные файлы устройств, обычно в /devman 4 tty
5форматы файлов и соглашенияman 5 passwd
6игрыman 6 fortune
7разное: соглашения, стандарты, сигналыman 7 signal
8административные команды, обычно для rootman 8 useradd

Таблица составлена по справке man man 8. Раздел 1 используется по умолчанию, поэтому man printf показывает страницу команды printf, а не функции C. Команда man 3 printf даёт функцию языка C, которая похожа по назначению, но принимает другие аргументы.

Встроенные команды описываются не отдельной страницей, а разделом SHELL BUILTIN COMMANDS справочной страницы bash. Поэтому man 1 type ничего не находит:

man 1 type
No manual entry for type in section 1

Поиск по описанию выполняет apropos, который является синонимом man -k:

apropos 'copy files'
cp (1)               - copy files and directories
cpio (1)             - copy files to and from archives

Внутри открытой страницы навигация выполняется программой less. Пробел и PageDown переходят на страницу вперёд, b возвращает назад, / начинает поиск вперёд, n и N переходят к следующему и предыдущему совпадению, q закрывает страницу. Поиск можно выполнить и без интерактивного режима, перенаправив вывод команде grep:

man ls | grep -n '^ *-l'
113:       -l     use a long listing format

Команда grep и её опции -n (номер строки) разбираются в теме 6.

Справка help, --help и info

Встроенные команды описаны в команде help. Она выводит краткую справку, в которой квадратные скобки обозначают необязательные части:

help cd
cd: cd [-L|[-P [-e]] [-@]] [dir]
    Change the shell working directory.

Внешние программы обычно принимают опцию --help, которая выводит краткую сводку опций:

ls --help | head -n 2
Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).

Итог можно сформулировать так. Для встроенной команды — help имя, для внешней программы — имя --help и man имя. Краткая справка показывает синтаксис, полная — все опции и примеры. Программа info (проект GNU) использует более подробный формат с гиперссылками; она установлена в среде, как и man. Сообщества пользователей также публикуют сокращённые страницы с примерами (утилита tldr); в среде подготовки она не установлена, поэтому в курсе не используется. Полная справка всегда доступна через man.

История команд

Оболочка сохраняет введённые команды в журнале, который выводит команда history. Номера команд нужны для повторного запуска. Пример сеанса: команды подаются на вход интерактивной оболочки, приглашение сокращено. Журнал записывается в отдельный временный файл, чтобы не смешивать его с историей пользователя.

printf 'echo first\necho second\n!!\ncat /etc/hostname !$\nhistory\n' | env -i HOME="$HOME" PATH="$PATH" TERM=dumb HISTFILE=/tmp/lin-hist-demo.txt bash --norc -i
bash-5.1$ echo first
first
bash-5.1$ echo second
second
bash-5.1$ !!
echo second
second
bash-5.1$ cat /etc/hostname !$
cat /etc/hostname second
lab-pc
cat: second: No such file or directory
bash-5.1$ history
    1  echo first
    2  echo second
    3  echo second
    4  cat /etc/hostname second
    5  history

Строка !! заменяется предыдущей командой и выводится перед результатом: это история-раскрытие (англ. history expansion). Выражение !$ заменяется последним аргументом предыдущей команды, поэтому вторая строка стала cat /etc/hostname second, и cat попыталась прочитать файл second. Такой эффект полезно помнить: раскрытие выполняется до запуска команды, и его результат нужно проверять. Команда history в полученном журнале показывает уже раскрытые строки. Полезные варианты: !n — повторить команду с номером n, !текст — повторить последнюю команду, начинающуюся с текста, history 10 — показать последние десять записей.

Поиск в журнале выполняется сочетанием клавиш Ctrl+R (англ. reverse-i-search). После нажатия появляется приглашение (reverse-i-search) с пустым поиском; каждый введённый символ сразу ищет совпадение в журнале назад по времени. Повторное нажатие Ctrl+R переходит к следующему совпадению, Enter выполняет найденную команду, а клавиши стрелок или Esc принимают её для редактирования. Ctrl+R особенно удобна для длинных команд, которые уже вводились, но запомнились только фрагментом.

Горячие клавиши readline

Редактирование строки выполняет библиотека GNU Readline, которую использует bash. Её функции описаны в руководстве по bash 3. Таблица 3 содержит клавиши, которые понадобятся чаще всего; обозначение C — Ctrl, M — Meta; в руководстве readline Meta означает клавишу, которая на современных клавиатурах соответствует Alt.

Таблица 3. Основные горячие клавиши bash (readline)

КлавишаФункция readlineДействие
Ctrl+Abeginning-of-lineпереход в начало строки
Ctrl+Eend-of-lineпереход в конец строки
Ctrl+B, Ctrl+Fbackward-char, forward-charсдвиг курсора на символ назад и вперёд
Alt+B, Alt+Fbackward-word, forward-wordсдвиг курсора на слово
Ctrl+Uunix-line-discardудалить текст от курсора до начала строки
Ctrl+Kkill-lineудалить текст от курсора до конца строки
Ctrl+Wunix-word-ruboutудалить слово перед курсором
Ctrl+Yyankвставить последний удалённый фрагмент
Ctrl+Lclear-screenочистить экран, оставив текущую строку вверху
Ctrl+Rreverse-search-historyпоиск по истории назад
Ctrl+P, Ctrl+Nprevious-history, next-historyпредыдущая и следующая команда истории
Alt+.yank-last-argвставить последний аргумент предыдущей команды
Ctrl+_ или Ctrl+X Ctrl+Uundoотменить последнее редактирование
Ctrl+Ddelete-char, на пустой строке — конец вводаудалить символ под курсором; на пустой строке закрыть оболочку
Tabcompleteавтодополнение имени команды, файла или каталога

Функции в таблице взяты из руководства bash: описания клавиш C-a, C-e, C-k, C-u, C-w, C-y, C-l, C-r, M-. и других приведены в разделе о командах Readline 3. Удаление фрагмента и его вставка через Ctrl+Y работают как буфер вырезания: удалённое сохраняется, и его можно вставить в другое место.

Ctrl+C — отдельный случай. Клавиша не относится к readline: терминал отправляет процессу сигнал прерывания SIGINT, и выполняемая команда останавливается. Сигналы рассматриваются в теме 7. Клавиша Tab заслуживает особого внимания: нажатие один раз дополняет имя, которое однозначно угадывается, а два нажатия подряд показывают все варианты. Привычка использовать Tab экономит время и уменьшает число опечаток, которые возникают при ручном наборе длинных имён.

Итоги темы

Тема ввела понятия, на которых держится работа в Linux. Операционная система состоит из ядра и пользовательских программ; Linux — ядро, которое вместе с программами GNU образует дистрибутив. История UNIX объясняет, почему система устроена как набор небольших программ, соединяемых текстом, а стандарт POSIX и проект GNU сделали этот набор переносимым. Терминал, эмулятор, консоль и оболочка — разные звенья одной цепочки: окно показывает символы, оболочка разбирает команду и запускает программу, программа обращается к ядру. Установка через WSL2 даёт настоящее ядро Linux внутри Windows, и её достаточно одной команды wsl --install.

Разобранный синтаксис — команда, опции, аргументы и кавычки — применяется ко всем последующим темам. Справка через man, help и --help позволяет проверять любую команду самостоятельно, а type объясняет, какую именно программу выполнит оболочка. Знание сочетаний клавиш readline и истории команд экономит время при каждой работе в терминале.

Следующая тема переходит от команд к данным: в теме 2 рассматриваются иерархия каталогов по стандарту FHS, пути, навигация и операции с файлами. Все примеры этой темы уже опирались на файлы и каталоги, поэтому знакомство с ними станет логическим продолжением.

Литература

  1. Shotts W. The Linux Command Line: A Complete Introduction. 2nd ed. — No Starch Press, 2019. Открытая версия: https://linuxcommand.org/tlcl.php
  2. Ritchie D. M., Thompson K. The UNIX Time-Sharing System. — Communications of the ACM, 1974, Vol. 17, No. 7, С. 365–375, DOI: 10.1145/361011.361061.
  3. Free Software Foundation. GNU Bash Reference Manual. — https://www.gnu.org/software/bash/manual/
  4. Nemeth E., Snyder G., Hein T. R., Whaley B., Mackin D. UNIX and Linux System Administration Handbook. 5th ed. — Addison-Wesley, 2017.
  5. Kernighan B. W., Pike R. The UNIX Programming Environment. — Prentice Hall, 1984.
  6. Raymond E. S. The Art of UNIX Programming. — Addison-Wesley, 2003. Открытая версия: http://www.catb.org/esr/writings/taoup/
  7. Microsoft. Документация WSL. — https://learn.microsoft.com/windows/wsl/
  8. The Linux man-pages project. — https://man7.org/linux/man-pages/
  9. Russinovich M. E., Solomon D. A., Ionescu A. Windows Internals. 7th ed. Part 1. — Microsoft Press, 2017.