Практический Linux для начинающих — читать книгу онлайн
Бесплатная книга по Linux: 16 глав о терминале, файлах, правах, процессах, сети и диагностике. Читайте полный текст онлайн или скачайте PDF с упражнениями и ответами.
Весь текст книги доступен ниже, включая упражнения, ответы и итоговый проект. Команды предназначены для собственной учебной Linux-системы; условия выполнения указаны в главах.
Как работать с книгой
Эта книга помогает освоить Linux через небольшие наблюдаемые действия. Вы создадите учебную мастерскую в домашнем каталоге, подготовите отчёт из журнала, ограничите доступ к файлу, разберётесь с процессом и составите план диагностики службы. Главный результат обучения - умение объяснить, что было проверено и почему полученный вывод относится к вашей задаче.
Читать главы лучше по порядку. Перед командой сформулируйте ожидаемый результат. После команды сравните ожидание с экраном и, если нужно, отдельно проверьте созданный файл. Если вывод отличается, остановитесь на этом месте: непонятный шаг редко исправляется механическим выполнением следующих десяти строк.
Для упражнений нужна уже установленная Linux-система с Bash и обычными GNU-утилитами. Подойдёт ваша учебная виртуальная машина или Linux-окружение, которым вы имеете право управлять. В книге нет процедуры переразметки диска или установки ОС. Глава о systemd применима только там, где этот менеджер действительно работает. В контейнере или некоторых конфигурациях WSL его может не быть.
Все команды набираются без приглашения терминала. Строки внутри блока «Ожидаемый результат» не нужно выполнять. Имена файлов и сообщения учебной мастерской придуманы для книги. Вывод, зависящий от машины, описан словами: ваш PID, имя пользователя и объём памяти не должны совпадать с чужим экраном.
Обычные упражнения выполняются от своей учётной записи, без sudo. Команды просмотра в главах о сети и службах не исправляют настройки автоматически. Если утилита отсутствует, сначала выясните её пакет и применимость к вашему окружению. Не подставляйте наугад команду из другого дистрибутива.
Книга предполагает интерактивную Bash с обычными настройками. Мы не включаем глобальный set -e: в упражнениях встречаются намеренно неуспешные команды, статус которых нужно изучить. Если вы уже настроили необычные alias или shell options, учитывайте их влияние и проверяйте разрешение команды через type.
В конце каждой главы есть самостоятельная задача. Разборы собраны отдельно, чтобы можно было попробовать решить её без подсказки. Финальный проект объединяет навыки, но использует только учебные файлы: вы не будете останавливать настоящую службу или менять сетевой доступ.
К оглавлению ↑1 Что находится между вами и программой
Терминал и оболочка
Терминал принимает клавиши и показывает текст. Оболочка читает командную строку, разделяет её на слова, выполняет подстановки и организует запуск. Linux как ядро управляет процессами, памятью и доступом к устройствам. Эта разница становится полезной сразу: ошибка кавычек возникает до того, как выбранная программа увидит свои аргументы.
Дистрибутив объединяет ядро, утилиты, библиотеки, установщик и правила обслуживания. Поэтому два компьютера с Linux могут иметь разные менеджеры пакетов и имена служб. Знакомое имя команды ещё не гарантирует одинаковый набор расширенных опций: в небольшом образе вместо GNU-версии иногда используется BusyBox.
Начните с трёх вопросов: в какой оболочке выполняется работа, кем вы вошли и где находитесь. Выполните:
printf 'Bash: %s\n' "$BASH_VERSION"
id
pwdПервая строка в Bash показывает её версию. id выводит числовые идентификаторы и группы. pwd показывает текущий каталог. Пустое BASH_VERSION в другой оболочке не означает отсутствие Linux; оно означает, что проверяемый признак Bash здесь не установлен.
Как читать команду
В строке ls -l -- . слово ls обозначает команду, -l меняет формат, -- завершает разбор опций, а точка задаёт текущий каталог. Пробелы разделяют аргументы. Символы внутри кавычек могут составлять одно имя, даже если в нём есть пробелы.
Часть команд, например cd, исполняется самой оболочкой. Это необходимо: внешний процесс не может обычным способом сменить рабочий каталог своего родителя. Другие команды запускают отдельную программу. Проверка type показывает, как Bash понимает конкретное имя в текущем сеансе.
type cd
type -a printf
type -a lsAlias и функция могут менять привычное поведение. Если вывод кажется неожиданным, сохраните результат type вместе с самой командой. Это полезнее, чем сообщить только «ls работает иначе».
Как закончить действие
Enter передаёт строку оболочке. Ctrl+C обычно прерывает текущую работу переднего плана, если программа не обрабатывает сигнал иначе. Ctrl+D передаёт признак конца ввода в обычной терминальной обработке; в пустом приглашении shell это часто завершает сеанс. Это разные действия, поэтому не используйте их как взаимозаменяемые кнопки.
Самостоятельно. Объясните, почему команда cd должна менять состояние оболочки, а просмотр файла через cat обычно может выполняться отдельным процессом. Затем найдите через type, что означает pwd в вашем сеансе.
К оглавлению ↑2 Учебная мастерская и первый результат
Выделяем место для опытов
Учебные команды должны работать с известными данными. Мы создадим новый каталог с непредсказуемым суффиксом, чтобы повторное занятие не затронуло прежние результаты. mktemp здесь создаёт каталог, а не только придумывает имя. Переменная LAB запомнит полный путь.
LAB=$(mktemp -d "$HOME/linux-book.XXXXXX")
printf 'Каталог занятия: %s\n' "$LAB"Продолжайте только если напечатан непустой путь и mktemp не сообщил об ошибке. Скопируйте путь в свои заметки. Если командой не удалось создать каталог, выясните причину: доступ к домашней папке, свободное место или отсутствие утилиты.
cd -- "$LAB"
pwd
mkdir -- input work reports
printf '%s\n' 'draft version' > input/note.txt
ls -l -- inputВ input должен появиться note.txt. У каталогов work и reports пока нет содержимого. Команда mkdir без -p здесь намеренно сообщает об уже существующих именах: для нового занятия ожидается новое дерево. Повторный запуск блока в той же папке требует понимания того, что уже создано.
Переменная живёт в сеансе
LAB не является постоянной настройкой системы. После закрытия терминала она может исчезнуть. Чтобы вернуться, откройте свой сохранённый полный путь через cd. Не набирайте случайно первое похожее имя из списка: у предыдущих занятий могут быть другие данные.
Все дальнейшие пути вида input/note.txt считаются относительно мастерской. Перед главой проверяйте pwd. Если работаете в новом сеансе, сначала вернитесь в нужную папку. Когда значение LAB требуется явно, задайте его своим сохранённым путём и проверьте существование каталога.
Команда printf '%s\n' 'draft version' передаёт заданный текст и перевод строки. Оболочка открывает назначение после >. Если файл уже был, его прежнее содержимое обычно обнуляется до запуска printf. Это причина, по которой мы не направляем учебный вывод в реальные конфигурационные файлы.
Ведём короткий журнал занятия
Записывайте исходный каталог, команду, результат и сделанный вывод. Например: «В input появился один обычный файл note.txt; командой cat подтверждено содержимое». Фраза «всё прошло нормально» не помогает найти ошибку при повторении.
cat -- input/note.txt
wc -l -- input/note.txtОжидаемый результат. cat показывает draft version, а wc сообщает одну строку и имя файла. Число считается по символу перевода строки, добавленному printf.
Самостоятельно. Создайте в work файл reminder.txt с одной строкой check the result. Убедитесь, что исходный input/note.txt не изменился. Отдельно запишите, какая команда создала файл, а какая только прочитала его.
3 Пути и имена файлов
Точка отсчёта
Абсолютный путь начинается с / и разрешается от корня, видимого процессу. Относительный путь начинается от текущего каталога. В пути work/../input/note.txt компонент .. возвращает к родителю work, если физическое разрешение пути не осложнено символьными ссылками. Лексическое сокращение пути со ссылками может дать неверное представление о фактическом объекте.
Точка обозначает текущий каталог, а .. - родительский. Корень остаётся корнем при попытке перейти выше него. Домашний каталог, текущий каталог и корень - три разных понятия. После перехода в /tmp ваш домашний путь не изменяется.
pwd
ls -ld -- . input work
ls -l -- work/../input/note.txtЗдесь -d просит показать свойства самого каталога. Без этой опции ls обычно перечислит его содержимое, и вы ответите на другой вопрос.
Кавычки сохраняют одно имя
printf '%s\n' 'packing list' > 'work/shift plan.txt'
cat -- 'work/shift plan.txt'Без кавычек между shift и plan оболочка передала бы два аргумента. Программа не знает, что человек задумал одно имя. Тот же принцип нужен для переменных: используйте "$LAB", чтобы значение с пробелами осталось одним аргументом.
Звёздочка в незаключённом в кавычки шаблоне обычно раскрывается оболочкой в подходящие имена. При отсутствии совпадения поведение зависит от настроек Bash. Поэтому шаблон для find заключается в кавычки: его должна получить сама утилита, а не заранее обработать shell.
Необычное имя не является опцией
printf '%s\n' 'temporary label' > work/-label.txt
cat -- work/-label.txtПолный относительный путь work/-label.txt не начинается с дефиса. Если вы находитесь внутри work, написание ./-label.txt сохраняет тот же смысл. У многих утилит -- завершает опции, но это не универсальное правило для любой программы: проверяйте её справку.
Linux допускает в имени даже перевод строки. Поэтому список ls подходит для просмотра человеком, но плохо подходит для надёжного разбиения имён в скрипте. В этой книге учебные имена простые; в настоящем автоматическом обходе выбирайте передачу аргументов или согласованные NUL-разделители.
Самостоятельно. Из корня мастерской прочитайте shift plan.txt двумя путями: через work и через work/../work. Объясните, почему пробел требует защиты в обоих вариантах.
К оглавлению ↑4 Создание копии и понятный возврат
Копия сохраняет исходник
Рабочую версию удобно отделять от входных данных. Обычное копирование создаёт назначение, которое можно изменить независимо от исходного файла. Это отличается от жёсткой ссылки: у неё два имени обращаются к одному объекту.
cp -- input/note.txt work/note.txt
printf '%s\n' 'revised version' > work/note.txt
cat -- input/note.txt work/note.txtОжидаемый результат. Последовательно показаны draft version и revised version. Cat не добавляет специального разделителя между файлами; граница видна потому, что каждый учебный файл заканчивается newline.
Если назначение уже существует, обычный cp может заменить его содержимое. Перед работой с важными данными проверьте точные имена и способ сохранения прежней версии. Наличие исходника не возвращает автоматически данные, которые раньше находились в назначении.
Перенос меняет расположение имени
mv -- work/note.txt work/note-reviewed.txt
ls -l -- work/note-reviewed.txtПосле успешного переноса старое имя work/note.txt отсутствует. В пределах одной файловой системы перенос часто является переименованием. Между файловыми системами реализация может копировать данные и затем удалять исходник; не рассчитывайте на одинаковую атомарность во всех случаях.
Сначала проверка потом удаление
Удаление через rm не обязано отправлять объект в корзину графического рабочего стола. Для упражнения создайте отдельный пустой файл, проверьте его имя и удалите ровно его. Каталог всей мастерской не требуется удалять для продолжения книги.
touch -- work/discard-me.txt
ls -l -- work/discard-me.txt
rm -i -- work/discard-me.txtПрочитайте вопрос rm и подтвердите только учебное имя. Флаг -i добавляет вопрос, но не превращает неверно выбранный путь в безопасный. Массовое удаление с рекурсией для этих упражнений не нужно.
Проверяем содержимое а не только имя
cmp -s -- input/note.txt work/note-reviewed.txt
comparison=$?
printf 'Код сравнения: %s\n' "$comparison"В этом упражнении код 1 означает различие содержимого. Код 0 означал бы совпадение, а 2 у GNU cmp - проблему сравнения. Статус нужно сохранить сразу: следующая команда сама обновит $?.
Самостоятельно. Сделайте в reports копию исходной заметки, убедитесь в её побайтовом совпадении с input/note.txt и только затем переименуйте копию в note-final.txt. Исходник должен остаться на месте.
К оглавлению ↑5 Чтение текста без догадок
Создаём журнал мастерской
Продолжайте в каталоге занятия. Создадим маленький журнал упаковки заказов. Это вымышленные записи, позволяющие заранее знать правильный ответ. В реальной диагностике журнал может содержать персональные сведения, поэтому перед передачей его другому человеку требуется отдельный просмотр.
printf '%s\n' \
'08:10 INFO order=41 packed' \
'08:12 WARN order=42 label_missing' \
'08:13 INFO order=43 packed' \
'08:17 ERROR order=44 printer_offline' \
'08:19 WARN order=45 label_missing' \
'08:22 INFO order=46 packed' > input/packing.logОбратная косая черта в конце строки продолжает команду на следующей строке. После неё не должно быть пробелов. Весь этот блок - один вызов printf с шестью строковыми аргументами.
head -n 2 -- input/packing.log
tail -n 2 -- input/packing.log
wc -l -- input/packing.logHead показывает начало, tail - конец, а wc сообщает шесть переводов строки. По одному хвосту нельзя понять всё содержимое файла: в последних двух записях нет ERROR, хотя в середине журнала она есть.
Строка и символ перевода строки
printf 'parcel' > work/no-newline.txt
wc -l -c -- work/no-newline.txtОжидаемый результат. Ноль переводов строки и шесть байтов. Человек видит слово, но wc -l считает именно newline. Для кириллицы или эмодзи число байтов UTF-8 может отличаться от числа символов. При сравнении хешей учитывается каждый байт, включая окончание строки.
Большой текст удобнее читать через less. В обычной настройке Space перелистывает вперёд, / начинает поиск, n ищет следующее совпадение, q завершает просмотр. Если less не установлен, head и tail всё равно позволяют получить ограниченный срез.
less -- input/packing.logЖурнал на настоящем сервере может изменяться во время чтения. Разовый tail показывает снимок. Режим наблюдения tail -f продолжает ожидать новые данные; остановить такое наблюдение обычно можно Ctrl+C. Поведение при замене файла ротацией требует отдельного выбора режима, поэтому не считайте любой tail -f наблюдением «навсегда».
Самостоятельно. Предскажите последние три записи packing.log и проверьте себя. Затем объясните, почему число видимых слов в no-newline.txt не равно результату wc -l.
К оглавлению ↑6 Поиск внутри файла и поиск самого файла
Отбор сообщений
Grep отвечает на вопрос о содержимом. Find отвечает на вопрос об объектах дерева. Чтобы не путать их, сформулируйте цель полностью: «найти строки с предупреждением в известном журнале» или «найти обычные файлы с суффиксом .log внутри input».
grep -Fn -- 'WARN' input/packing.logОжидаемый результат. Найдены строки 2 и 5. Опция -F задаёт буквальный поиск, а -n добавляет номер строки. Если позже журнал изменится, номера могут стать другими: это не постоянные идентификаторы событий.
Шаблон регулярного выражения имеет другой смысл. Точка в нём обычно означает произвольный символ, а квадратные скобки задают класс. Если ищете точную надпись, начинайте с -F. Это уменьшает число правил, которые нужно одновременно держать в голове.
grep -F -- 'CANCELLED' input/packing.log
search_status=$?
printf 'Статус поиска: %s\n' "$search_status"Здесь GNU grep возвращает 1: файл прочитан, выбранных строк нет. Отсутствие совпадения не тождественно ошибке открытия. Код 2 обычно означает ошибку обработки. Всегда смотрите и на сообщение stderr; режим -q имеет особенности раннего завершения, поэтому пока используйте обычный вывод.
Поиск по дереву
find input -type f -name '*.log' -printОжидаемый результат. input/packing.log. Указание начальной точки input ограничивает область. Оно не доказывает, что других журналов нет во всей системе. Кавычки сохраняют шаблон *.log для find.
Пустой результат при отказах доступа не означает, что совпадений нет в недоступных ветках. Не добавляйте sudo только ради исчезновения сообщения: сначала определите, действительно ли вам нужно читать эту область и разрешено ли это.
Когда нужен просмотр, не добавляйте к find действия удаления или исполнения. В этой главе -print явно обозначает желаемый результат. Нужное действие важнее количества опций в строке.
Самостоятельно. Получите только записи с label_missing. Потом найдите обычные txt-файлы внутри work. Объясните, почему замена grep на find не решит первую задачу.
К оглавлению ↑7 Потоки и проверка каждого этапа
Соединяем вывод и вход
Стандартный ввод stdin обычно имеет номер 0, вывод результата stdout - 1, диагностика stderr - 2. Обычный символ | направляет stdout левого звена на stdin правого. Диагностика остаётся отдельной, если вы явно не изменили её назначение.
grep -F -- 'WARN' input/packing.log | wc -lОжидаемый результат. 2. Grep выбирает две записи и передаёт их дальше, а wc считает переводы строки. Промежуточный файл для этой передачи не нужен.
grep -F -- 'WARN' input/packing.log > reports/warnings.txt
cat -- reports/warnings.txtТеперь результат сохраняется. Символ > открывает назначение с обычным усечением прежнего содержимого, а >> добавляет вывод. Настройка noclobber может запретить обычную перезапись через >. В любом случае путь назначения нужно проверить до выполнения команды.
Почему ноль не доказывает исправность
grep -F -- 'WARN' input/absent.log | wc -l
pipeline_status=$?
printf 'Общий статус: %s\n' "$pipeline_status"Источник сообщил об отсутствии файла, а wc мог успешно вывести 0. В Bash без pipefail общий статус принадлежит последнему звену и здесь будет 0. Система не утверждает, что предупреждений не было; успешным оказался только подсчёт полученного пустого входа.
Чтобы увидеть статусы всех звеньев в Bash, сохраните PIPESTATUS сразу после pipeline:
grep -F -- 'WARN' input/absent.log | wc -l
stage_status=("${PIPESTATUS[@]}")
printf 'grep=%s wc=%s\n' \
"${stage_status[0]}" "${stage_status[1]}"В этом опыте ожидается grep=2 и wc=0. Любая следующая команда меняет сведения о последнем pipeline, поэтому массив копируется до printf.
Порядок перенаправлений
В записи command > result.txt 2>&1 сначала stdout направлен в файл, затем stderr получает то же назначение. В записи command 2>&1 > result.txt stderr дублирует прежний stdout, и только после этого stdout переходит в файл. Выполнять абстрактное слово command не требуется: здесь описано правило чтения строки.
Самостоятельно. Сохраните строки ERROR в отдельный файл reports/errors.txt и проверьте число строк. Затем назовите две причины, по которым пустой отчёт нельзя автоматически считать отсутствием ошибок приложения.
К оглавлению ↑8 Сортировка и простые отчёты
Сначала определяем единицу подсчёта
В отчёте можно считать строки, слова, уникальные значения или соседние серии повторов. Эти ответы относятся к разным вопросам. Создадим список направлений доставки, в котором один и тот же пункт встречается в нескольких местах.
printf '%s\n' north south north west south north \
> input/directions.txt
LC_ALL=C sort -- input/directions.txt | LC_ALL=C uniq -cОжидаемый результат. north встречается 3 раза, south - 2, west - 1. Сортировка собирает одинаковые строки рядом, затем uniq -c считает соседние группы. Один uniq без sort не объединит разнесённые повторения.
Локаль C выбрана для воспроизводимого порядка этих ASCII-слов. Она не является правильным языковым порядком для любого русского текста. Если порядок важен при обмене отчётами, запишите используемую локаль вместе с командой.
Текстовые числа могут сортироваться неожиданно
printf '%s\n' 3 20 100 > input/counts.txt
LC_ALL=C sort -- input/counts.txt
sort -n -- input/counts.txtЛексический порядок этих строк - 100, 20, 3. Числовой порядок - 3, 20, 100. Опция -n помогает с числами, но не превращает произвольную строку «около двадцати» в надёжные числовые данные. Формат входа должен быть определён заранее.
Поля требуют согласованного разделителя
printf '%s\n' 'north:3:ready' 'south:2:waiting' \
> input/summary.txt
cut -d : -f 1,3 -- input/summary.txtОжидаемый результат. north:ready и south:waiting. Cut выбирает поля, разделённые указанным символом. Это не универсальный анализатор CSV: кавычки и разделители внутри полей требуют другого парсера.
Если строки без разделителя недопустимы, рассмотрите -s. Если между колонками произвольное число пробелов, сначала уточните формат, а не подставляйте один пробел как будто это всегда один разделитель.
Самостоятельно. Постройте отчёт reports/direction-counts.txt с числами для каждого направления и проверьте, что сумма равна шести. Измените только одну входную строку и предскажите, какие две группы изменятся.
К оглавлению ↑9 Доступ к файлам и каталогам
Читаем обычные биты режима
В длинном выводе ls первый символ показывает тип, затем идут три тройки rwx: владелец, группа, остальные. Для обычного файла r позволяет читать, w - изменять содержимое, x участвует в разрешении исполнения. Реальная проверка доступа также учитывает путь, владельцев, ACL, политики безопасности и другие условия.
Для каталога смысл иной. Чтение связано с перечислением имён, запись - с изменением записей каталога, а x - с поиском и проходом. Поэтому режим файла сам по себе не даёт доступ через закрытый родительский каталог. Удаление имени определяется прежде всего правами на каталог, а не записью в содержимое самого файла; sticky bit добавляет ограничения.
cp -- input/note.txt work/private.txt
chmod 600 -- work/private.txt
ls -l -- work/private.txtОжидаемый результат. В обычных битах видна запись rw-------. Цифра 6 составлена из чтения 4 и записи 2, а следующие нули не дают обычных разрешений группе и остальным.
Классы не складываются произвольно
Если процесс совпал с владельцем, при обычной проверке используются биты владельца; более широкие биты «остальных» не дополняют их автоматически. Правильный вопрос начинается с того, кто обращается к объекту. Команда id относится к процессу наблюдателя, а ls -l - к выбранному объекту.
id
stat -c '%u:%g %a %n' -- work/private.txt
namei -l -- work/private.txtNamei из util-linux показывает компоненты пути. Если она отсутствует, последовательно смотрите свойства доступных родителей через ls -ld. При обычных битах без очевидной причины отказа проверяют ACL через getfacl, а затем применимые политики. Не исправляйте неизвестную причину выдачей 777.
Новые файлы и маска
Umask удаляет биты из режима, запрошенного при создании. В типичном случае без default ACL запрос 666 и маска 027 дают 640. Execute не появляется, если программа не запрашивала его. Изменение umask не переписывает существующие файлы.
( umask 077; printf '%s\n' 'local draft' > work/masked.txt )
stat -c '%a %n' -- work/masked.txtСкобки ограничивают изменение маски дочерней оболочкой. При новом файле и обычных условиях ожидается 600. Если файл уже существовал, этот опыт не измеряет создание: выберите новое учебное имя.
Самостоятельно. Поменяйте private.txt на 640. Объясните каждую цифру и назовите две проверки, которые нужны дополнительно к чтению режима.
К оглавлению ↑10 Переменные и небольшой сценарий
Значение и передача дочернему процессу
Переменная оболочки хранит значение в текущем сеансе. Export отмечает её для передачи новым внешним программам через окружение. Изменение окружения дочернего процесса не переписывает значение родителя.
BOOK_TOPIC=files
printf 'Текущая тема: %s\n' "$BOOK_TOPIC"
BOOK_TOPIC=processes bash -c 'printf "%s\n" "$BOOK_TOPIC"'
printf 'После запуска: %s\n' "$BOOK_TOPIC"Ожидаемый результат. Сначала files, затем processes, затем снова files. Временное назначение перед запуском bash относится к её окружению. Одинарные кавычки удерживают строку программы для дочерней Bash; подстановка выполняется уже внутри неё.
Сценарий должен проверять вход
Повторяющийся отчёт удобно описать один раз. Создадим скрипт, который принимает имя журнала и печатает число предупреждений. Сначала он получает полный вывод grep и сохраняет статус, а затем считает строки. Это позволяет отличить «совпадений нет» от «файл не прочитан».
cat > work/count-warnings.sh <<'BASH'
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
printf 'Usage: count-warnings.sh FILE\n' >&2
exit 2
fi
selected=$(grep -F -- 'WARN' "$1")
status=$?
if [ "$status" -gt 1 ]; then
printf 'Cannot read the input reliably\n' >&2
exit "$status"
fi
if [ "$status" -eq 1 ]; then
printf '0\n'
else
printf '%s\n' "$selected" | wc -l
fi
BASH
bash -n work/count-warnings.sh
bash work/count-warnings.sh input/packing.logОжидаемый результат. Проверка bash -n молчит при отсутствии синтаксической ошибки; второй вызов выводит 2. Кавычки вокруг BASH у оператора here-document запрещают подстановки во время создания файла. Без них переменные могли бы раскрыться слишком рано.
Этот небольшой скрипт рассчитан на учебный текст, который помещается в память. Command substitution удаляет завершающие newline; в данном примере выбранные строки содержат WARN, поэтому восстановление одного конечного newline сохраняет число таких строк. Для больших журналов нужен потоковый подход или временный файл с собственной проверкой.
Синтаксическая проверка не доказывает правильность алгоритма. Испытайте скрипт на трёх случаях: журнал с предупреждениями, читаемый файл без них и отсутствующий путь. Во втором случае нужен 0 как результат; в третьем - ненулевой статус и диагностика.
Самостоятельно. Скопируйте скрипт под другим именем и измените его для подсчёта ERROR. На исходном журнале ответ должен быть 1. Сохраните различие между пустым отбором и ошибкой чтения.
К оглавлению ↑11 Процессы и завершение работы
Программа на диске и программа в памяти
Файл программы может существовать без запуска. Процесс появляется при выполнении и имеет идентификатор, память, открытые ресурсы и учётные данные. Несколько запусков одной программы обычно дают несколько процессов.
ps -p "$$" -o pid,ppid,user,stat,commВ обычном интерактивном Bash $$ относится к оболочке. Столбец PPID показывает родителя в доступном представлении процессов. Значения зависят от сеанса, поэтому переписывать чужой PID в команду управления нельзя. PID может повторно использоваться после завершения старого процесса.
Создаём только свой процесс
Выполните следующий опыт подряд, в одном терминале. Sleep ничего не меняет в файлах; он просто ожидает. Сохранённый идентификатор относится к только что запущенной работе.
sleep 120 &
book_child=$!
ps -p "$book_child" -o pid,ppid,stat,comm
kill -TERM "$book_child"
wait "$book_child"
child_status=$?
printf 'Статус завершения: %s\n' "$child_status"Убедитесь в строке ps, что перед вами именно ваш sleep, прежде чем послать сигнал. Если вы прервали занятие и вернулись значительно позже, не используйте старый номер: создайте новый учебный процесс. Завершение от TERM обычно даёт ненулевой статус; не требуйте числа 0 как признака успеха этого опыта.
Kill отправляет сигнал, а не обязательно немедленно уничтожает процесс. TERM позволяет программе применить обработчик и закончить работу. KILL нельзя перехватить; он не даёт приложению выполнить своё обычное завершение. Начинать диагностику неизвестной службы с KILL - плохой способ сохранить данные и причину сбоя.
Фон не делает задачу независимой
Знак & освобождает приглашение оболочки, но не обещает, что процесс переживёт закрытие терминала. Для длительной службы нужен предусмотренный способ запуска и контроля. Jobs показывает работы текущей оболочки, а ps - процессы в доступной системе: это разные списки.
Запись зомби означает, что выполнение уже завершено, но статус ещё ожидает сбора. Посылать такой записи новый KILL бессмысленно. Важно разобраться с родительским процессом и механизмом ожидания, а не многократно повторять сигнал.
Самостоятельно. Запустите sleep 2 в фоне, сразу сохраните $! и дождитесь его через wait. Как отличить этот обычный конец ожидания от опыта с TERM?
К оглавлению ↑12 Место на диске и оперативная память
Сначала выясняем область измерения
Если запись не удалась, фраза «диск заполнен» пока является гипотезой. Целевой путь может находиться на отдельной файловой системе, а свободные байты домашнего диска ничего не говорят о ней. Выполните просмотр в мастерской:
df -h -- .
df -i -- .
du -sh -- input work reportsDf описывает файловую систему указанного пути, du обходит выбранные деревья. Первый ответ относится к свободному месту, второй - к inode, третий - к данным, доступным при обходе. Эти числа не обязаны складываться в простое равенство.
У многих небольших файлов могут закончиться inode при оставшихся байтах. Квоты, режим только чтения и запрет доступа также мешают записи. Удалённый файл может продолжать занимать место, пока процесс удерживает его открытым. Поэтому большое расхождение df и du требует изучения, а не удаления случайных каталогов.
Память не сводится к одной цифре
free -h
ps -e -o pid,rss,comm --sort=-rssПамять файлового кэша может помогать работе системы. Малое free само по себе не доказывает нехватку памяти. MemAvailable - оценка памяти, доступной для новой нагрузки без перехода к подкачке в обычном смысле этого показателя; она не гарантирует успех произвольного запроса приложения.
RSS показывает резидентные страницы процесса, но общие страницы могут попадать в несколько строк. Сумма RSS не является точной уникальной стоимостью всех процессов. Чтобы исследовать конкретную программу, запишите её PID, время наблюдения и изменение показателя под понятной нагрузкой.
Сравниваем во времени
vmstat 1 5В стандартном выводе vmstat первая строка счётчиков имеет другую временную базу, часто с момента загрузки; дальнейшие строки относятся к интервалам. Не сравнивайте накопленное среднее с секундным всплеском как одинаковые измерения.
В контейнере видимость памяти и лимиты могут отличаться от всего хоста. Ограничение cgroup относится к конкретной ветви процессов; доступная память хоста не отменяет этот предел. Перед выводом об утечке выясните область каждого показателя.
Самостоятельно. Сохраните в заметках файловую систему, на которой расположена мастерская, и отдельно число доступных inode. Объясните, почему большой объём RAM не устраняет заполнение диска.
К оглавлению ↑13 Служба и её журнал
Уточняем наличие systemd
Служба выполняет длительную или событийную работу. Systemd управляет объектами unit разных типов. Наличие команды systemctl на диске ещё не означает, что в данном окружении доступен работающий менеджер.
ps -p 1 -o comm=
systemctl --failed --no-pagerЕсли systemctl сообщает, что система не загружена с systemd или шина недоступна, эта глава остаётся знакомством с методом. Не пытайтесь исправить учебный контейнер случайной установкой пакетов. Сначала определите предназначенный способ управления его процессами.
Разделяем состояние и полезную работу
Выберите существующую службу, которую разрешено просматривать. Сначала получите список, затем задайте UNIT её точным именем. Строка с заполнителем ниже не является именем готовой службы: замените её результатом своего списка.
systemctl list-units --type=service --no-pager
UNIT='имя-из-вашего-списка.service'
systemctl status "$UNIT" --no-pager
systemctl is-enabled "$UNIT"
journalctl -u "$UNIT" -b -n 30 --no-pagerActive описывает текущее состояние unit. Enabled относится к связям запуска. Они могут различаться: работающая служба бывает не включена в обычный автозапуск, а включённая может быть остановлена. Некоторые unit имеют состояние static и запускаются через другие механизмы.
Даже active не гарантирует полезный ответ приложения. Сервер может быть запущен, но возвращать ошибку на нужный запрос. Поэтому проверка включает наблюдение менеджера и отдельную проверку функции, важной пользователю.
Журнал нужен вместе с контекстом
Опция -b ограничивает текущую загрузку, -u выбирает unit, -n задаёт последние записи выбранного набора. Пустой вывод может быть связан с фильтрами, правами доступа или правилами хранения. Он не доказывает отсутствия ошибок.
Различайте restart, reload и daemon-reload. Restart останавливает и запускает службу, если применим. Reload просит приложение перечитать настройки, когда это поддержано. Daemon-reload перечитывает определения unit менеджером и сам по себе не гарантирует применение новой конфигурации внутри приложения.
В этой главе мы не выполняем изменения. Сначала нужно знать, кто пользуется службой, что будет прервано, как проверяется результат и как возвращается сохранённая конфигурация.
Самостоятельно. Для разрешённой службы запишите три независимых факта: состояние unit, состояние запуска и одно свежее сообщение журнала. Отдельно сформулируйте, какая прикладная проверка ещё нужна.
К оглавлению ↑14 Адрес маршрут имя и порт
Разделяем сетевые вопросы
Сообщение «не открывается» слишком широко. Приложению нужно разрешить имя, выбрать маршрут, установить обмен с нужным адресом и портом и получить корректный ответ протокола. Сбой возможен на каждом этапе. Диагностика движется по наблюдениям, а не по привычке перезагружать сеть.
ip -br address show
ip -4 route show
ip -4 rule showПервый вывод показывает адреса и интерфейсы. Второй - обычную основную IPv4-таблицу, третий - правила выбора таблиц. У интерфейса может быть несколько адресов. Слово UP само по себе не доказывает доступность конкретного сервиса.
Решение о маршруте не посылает запрос приложению
ip -4 route get 192.0.2.33Адрес выбран из диапазона для документации. Этот опыт рассматривает решение вашей таблицы, а не доступность публичного сервера. Команда может сообщить об отсутствии маршрута - это тоже содержательный результат.
В простой таблице выбирается наиболее длинный подходящий префикс. Меньшая метрика менее точного маршрута не обязана победить более точный. В настоящей системе сначала нужно учесть правила, типы маршрутов и другие условия; одной упрощённой схемы недостаточно для любого сетевого окружения.
Разрешение имени
getent ahosts localhost
grep '^hosts:' /etc/nsswitch.confGetent обращается к системному механизму разрешения. В него может входить локальный файл hosts и другие источники, поэтому не всякое разрешение имени является DNS-запросом. Несколько похожих строк в ahosts могут относиться к разным типам сокетов.
Слушающий сокет
ss -ltn
ss -lunTCP и UDP используют разные транспортные пространства. Номер 443 не доказывает, что процесс действительно обслуживает HTTPS. Привязка к 127.0.0.1 ограничивает приём loopback-адресом в данном сетевом пространстве. Wildcard-привязка также не отменяет firewall или другие ограничения доставки.
Если приложение слушает локально, это ещё не означает успешный доступ извне. Если ping не ответил, это не доказывает отказ HTTP: ICMP и прикладной обмен проверяют разные свойства. Записывайте точный симптом и переходите к следующему различающему наблюдению.
Самостоятельно. Назовите отдельные проверки для трёх случаев: имя не разрешается, маршрут отсутствует, соединение отвергнуто. Не предлагайте изменение firewall до выяснения причины.
К оглавлению ↑15 Пакеты справка и доверие к команде
Находим происхождение утилиты
Неизвестную команду полезно связать с пакетом и реализацией. Начните с локальных сведений о системе. Значения VERSION_ID и ID относятся к дистрибутиву; версия ядра из uname -r отвечает на другой вопрос.
cat /etc/os-release
uname -r
type -a grep
grep --versionЕсли GNU-опция --version не поддержана, изучите доступную справку конкретной реализации. Не заключайте из этого, что «Linux сломан».
Для установленного пакета выберите только команду своего семейства. Эти запросы не требуют устанавливать или удалять что-либо:
# Debian и Ubuntu
dpkg-query -W bash
# Системы с RPM
rpm -q bash
# Arch Linux
pacman -Q bashНе выполняйте весь блок в ожидании трёх одинаковых ответов. В обычной системе часть менеджеров отсутствует. Имена пакетов, политика выпусков и доступные версии различаются.
Читаем справку по задаче
В man сначала найдите назначение и синтаксис, затем нужную опцию, описание результата и кодов завершения. Примеры удобны, но не заменяют ограничений. В встроенной справке Bash команда help cd описывает builtin, а man может открывать другой уровень документации.
help cd
man grepЕсли man открывает pager, для выхода обычно подходит q. Отсутствие локальной man-страницы может означать, что документация не установлена отдельно. Это не делает случайную статью с незнакомой командой равнозначной документации используемой версии.
Проверяем прежде чем применять
Разберите путь назначения, опции изменения и подстановки. Выясните, нужны ли полномочия администратора. Установка пакета меняет систему и может запускать служебные действия; подключение нового репозитория меняет доверенные источники последующих обновлений. Такие операции выполняют по правилам своей машины, с пониманием результата и возврата.
Копирование скрипта из сети прямо в shell не оставляет удобного этапа изучения. Для обучения полезнее сначала прочитать файл и объяснить его действия. Команда с привлекательным названием «исправить всё» не содержит доказательств, что подходит именно вашей ошибке.
Самостоятельно. Для grep запишите реализацию, версию и смысл -F. Затем объясните, почему версия ядра не определяет версию grep.
К оглавлению ↑16 Итоговый проект Отчёт смены
Постановка задачи
Вы помогаете вымышленной мастерской подготовить сводку упаковки. Нужны две записи WARN из packing.log, отдельная запись ERROR, число каждого класса и сохранённый исходник. Отчёты должны оставаться внутри мастерской. Публиковать реальные журналы или подключаться к сети не требуется.
Перед началом вернитесь в каталог занятия и убедитесь, что исходный журнал содержит шесть строк из главы 5. Если вы меняли его для опытов, создайте заново по приведённому там блоку. Теперь попробуйте решить задачу без готового решения из следующего раздела.
Требования к результату:
- reports/shift-warnings.txt содержит только две WARN-записи в исходном порядке.
- reports/shift-errors.txt содержит одну ERROR-запись.
- reports/shift-counts.txt содержит строки WARN=2 и ERROR=1.
- Обычные биты обоих файлов с событиями равны 600.
- Содержимое input/packing.log совпадает с копией reports/packing-original.log.
Разбор рабочего решения
cp -- input/packing.log reports/packing-original.log
grep -F -- 'WARN' input/packing.log > reports/shift-warnings.txt
grep -F -- 'ERROR' input/packing.log > reports/shift-errors.txt
chmod 600 -- reports/shift-warnings.txt reports/shift-errors.txt
printf 'WARN=%s\nERROR=%s\n' \
"$(wc -l < reports/shift-warnings.txt)" \
"$(wc -l < reports/shift-errors.txt)" > reports/shift-counts.txtВыполняйте команды по одной и проверяйте сообщения. В заранее известном журнале оба grep должны вернуть 0. Для неизвестного входа полноценный скрипт обязан отдельно обработать отсутствие совпадений и ошибку чтения; глава 10 показывает это различие.
cat -- reports/shift-counts.txt
cat -- reports/shift-warnings.txt reports/shift-errors.txt
stat -c '%a %n' -- reports/shift-warnings.txt reports/shift-errors.txt
cmp -s -- input/packing.log reports/packing-original.log
source_status=$?
printf 'Сравнение исходника: %s\n' "$source_status"Здесь проверяются содержание, права и сохранность исходника. Одного существования файлов недостаточно: пустой файл тоже существует, а ошибочно сформированный отчёт может иметь правильный режим.
Разбираем намеренную ошибку
Представьте, что автор отчёта заменил вход на input/packing-old.log, которого нет, и получил 0 после pipeline с wc. Какое утверждение доказано? Только то, что правое звено посчитало полученный вход. Чтобы восстановить отчёт, сначала исправляют путь и проверяют источник. Выдача дополнительных прав не создаст отсутствующий файл.
Другой случай: файл есть, но ожидаемых строк нет. Проверьте точное написание WARN, регистр, выбранный журнал и период. Фильтр буквального текста решает простую задачу; он не понимает структуру произвольного формата журналирования.
Критерий самостоятельной работы
Проект завершён, если вы можете повторить его в новом каталоге, получить те же учебные числа и объяснить каждую проверку. Сохраните короткую запись: входные данные, команды, наблюдения и ограничения. Такой отчёт пригодится значительно дольше, чем снимок одного удачного экрана.
К оглавлению ↑Разбор самостоятельных заданий
Глава 1
Cd меняет рабочий каталог самой оболочки: именно от него будут разрешаться пути следующей команды. Отдельный дочерний процесс мог бы изменить только собственный каталог. Cat читает выбранные данные и передаёт результат через stdout, поэтому ему обычно не требуется менять состояние родителя. Проверка type pwd в Bash часто показывает встроенную команду, но проверять нужно свой сеанс.
Глава 2
В мастерской выполните printf '%s\n' 'check the result' > work/reminder.txt. Затем прочитайте reminder.txt и исходный note.txt через cat. Создание связано с открытием назначения оболочкой и выводом printf; cat только проверяет содержимое. Исходная заметка должна содержать draft version.
Глава 3
Оба варианта читают одно учебное имя: cat -- 'work/shift plan.txt' и cat -- 'work/../work/shift plan.txt'. Кавычки нужны из-за пробела внутри имени. Компоненты пути не отменяют разделения аргументов оболочкой.
Глава 4
Скопируйте input/note.txt в reports/note-check.txt. Выполните cmp -s для этих двух файлов и сразу сохраните $?. При коде 0 переименуйте копию через mv в reports/note-final.txt. Если cmp сообщает проблему, не трактуйте её как подтверждённое различие: сначала разберите диагностику и имена.
Глава 5
Последние три записи относятся к 08:17, 08:19 и 08:22. Проверка - tail -n 3 -- input/packing.log. В no-newline.txt шесть байтов ASCII и ни одного newline, поэтому wc -l показывает 0. Видимый фрагмент текста и подсчитанный разделитель - разные объекты наблюдения.
Глава 6
Для содержимого подходит grep -F -- 'label_missing' input/packing.log. Для файлов - find work -type f -name '*.txt' -print. Первая команда проверяет строки, вторая - имена и типы объектов в дереве. Нахождение файла не означает, что нужное слово есть внутри него.
Глава 7
Направьте результат grep -F -- 'ERROR' input/packing.log в reports/errors.txt, затем прочитайте файл и примените wc -l. Ожидается одна запись. Пустота могла возникнуть из-за отсутствия подходящих событий или отказа чтения источника; неверный фильтр даёт ещё одну отдельную гипотезу.
Глава 8
Используйте LC_ALL=C sort -- input/directions.txt | LC_ALL=C uniq -c > reports/direction-counts.txt. Три, два и один дают шесть. Если заменить один north на west, количества станут два, два и два. Сначала измените вход, затем пересоздайте отчёт: прежний файл не пересчитывается сам.
Глава 9
Команда chmod 640 -- work/private.txt оставляет владельцу чтение и запись, группе чтение, остальным не даёт обычных битов. Дополнительно проверьте, чей процесс обращается к файлу, и доступ по родителям. При необходимости отдельно изучите ACL и применимые политики безопасности.
Глава 10
В копии сценария замените только буквальный образец WARN на ERROR, сохранив проверку статуса. Для packing.log результат равен 1. Для читаемого файла без ERROR результат 0 является нормальным ответом; для отсутствующего пути нужен ненулевой код сценария. Нельзя объединять эти два случая одним сообщением «ошибок нет».
Глава 11
После sleep 2 & сохраните $! в отдельной переменной и вызовите wait с этим значением. Обычное завершение sleep даёт статус 0. В опыте с TERM процесс завершался сигналом и возвращаемый оболочкой статус был ненулевым. Сообщение shell об окончании задания может появиться отдельно от printf.
Глава 12
Сопоставьте строки df -h . и df -i . по выбранной файловой системе. RAM используется для памяти процессов и кэша; свободное место для постоянной записи относится к хранению. Возможность временно держать данные в памяти не гарантирует их последующего сохранения на заполненный диск.
Глава 13
Статус unit, состояние is-enabled и запись журнала нужно сохранить отдельно. Прикладная проверка зависит от назначения: например, для разрешённого веб-приложения это запрос к конкретной функции и проверка содержимого ответа. Универсального факта «процесс существует, значит всё исправно» нет.
Глава 14
При отказе разрешения имени сначала изучают результат системного resolver и его конфигурацию. При отсутствии маршрута проверяют адрес назначения, правила и таблицы. При отказе соединения исследуют адрес привязки, listener, путь доставки и возможный явный reject. Ни один из этих симптомов не задаёт заранее единственное изменение firewall.
Глава 15
Grep --version и локальная справка относятся к утилите обработки текста. Uname -r сообщает выпуск работающего ядра. Эти компоненты обновляются и поставляются отдельно, поэтому номер одного не вычисляет номер другого. Опция -F выбирает фиксированные строки; метасимволы регулярного выражения не получают специального значения.
К оглавлению ↑Памятка для самостоятельной диагностики
Начните с наблюдаемой проблемы
Запишите, какое действие не удалось, когда это произошло и что ожидалось. «Команда завершилась кодом 2 и сообщила об отсутствии input/packing.log» полезнее фразы «Linux не работает». Если есть графическое сообщение, перепишите его точно, включая имя объекта, но уберите реальные секреты перед передачей заметки.
Подтвердите контекст
Укажите машину или учебную среду, пользователя, текущий каталог и реализацию команды. Для сети добавьте адрес, порт и протокол, для службы - точное имя unit и выбранную загрузку, для файла - полный путь. Ошибка в контексте способна сделать правильную команду бесполезной.
Выберите проверку которая различает причины
Если предположения одинаково предсказывают результат команды, эта команда пока не помогает выбрать между ними. Проверка существования пути отличает отсутствующий файл от неправильного фильтра. Просмотр stderr отличает отказ чтения от пустого успешного отбора. Проверка listener отделяет запуск процесса от приёма соединений.
Изменяйте одно понятное условие
Перед правкой сохраните затрагиваемый исходник и определите способ применения. Не смешивайте смену прав, перенос файла и перезапуск службы в одну попытку без промежуточных наблюдений. Иначе после успеха будет трудно объяснить, что именно помогло, а после отказа - что нужно вернуть.
Проверьте результат на уровне задачи
Если требовался отчёт, прочитайте его и сравните количество событий. Если требовался доступ, выполните разрешённую операцию нужной учётной записью. Если требовалась функция сервиса, проверьте функцию. Успешное выполнение команды управления - только одно звено доказательства.
Сохраните границы вывода
Укажите, что осталось непроверенным. Локальный успех не подтверждает удалённую доступность. Один снимок не описывает поведение весь день. Учебный пример не является нагрузочным тестом. Такая запись делает результат точнее и помогает следующему человеку продолжить работу.
К оглавлению ↑Дальнейшее обучение и технические ориентиры
После этой книги полезно самостоятельно повторить итоговый проект с новым журналом и заранее рассчитанным ответом. Затем можно расширять навыки: изучать структуру файловой системы, подробности Bash, управление пакетами своей системы, службы и сетевые протоколы. Каждый новый инструмент лучше добавлять для конкретной задачи, а не ради длины списка знакомых команд.
Для уточнения фактов используйте документацию установленной реализации. Основные технические ориентиры книги: GNU Bash Reference Manual, GNU Coreutils Manual, GNU Grep Manual, GNU Findutils Manual, Linux man-pages, документация util-linux, procps-ng, iproute2 и systemd. Названия приведены для идентификации; активных внешних ссылок в книге нет.
Сборка системы из исходных компонентов - следующий самостоятельный уровень обучения. Для неё нужны дополнительные знания о компиляторе, библиотеках, загрузке и воспроизводимости сборки. Освоение просмотра файлов и процессов создаёт полезную основу, но не заменяет проверку требований конкретного руководства и текущих версий компонентов.
Разобранные здесь задачи имеют ограниченный учебный масштаб. При работе с чужим сервером или важными данными к техническим навыкам добавляются согласованный доступ, резервирование и правила обслуживания. Сначала определите границы своей задачи, затем выбирайте действия, которые можете объяснить и проверить.
К оглавлению ↑От материала к практике
Выберите следующую тему в каталоге Linux или проверьте знакомые команды в учебном терминале.