Практика 2. Процессы, мониторинг и скрипты
Цель работы
Научиться исследовать и управлять процессами в Linux, освоить мониторинг системы, написание bash-скриптов.
Часть 1. Исследование процессов
Задание 1.1. Просмотр процессов
-
Выведите список всех процессов в системе:
Окно терминала ps auxОбъясните значение столбцов:
USER,PID,%CPU,%MEM,VSZ,RSS,STAT,START,COMMAND. -
Найдите процесс текущей оболочки:
Окно терминала ps aux | grep $$echo "Мой PID: $$"echo "PID родителя: $PPID" -
Выведите дерево процессов:
Окно терминала pstree -pНайдите в дереве
systemd(PID 1). Какие процессы являются его прямыми потомками? -
Исследуйте процесс через
/proc:Окно терминала cat /proc/$$/status | head -20cat /proc/$$/cmdlinels -la /proc/$$/fd/Что содержит каталог
/proc/<pid>/fd/?
Задание 1.2. Мониторинг в реальном времени
-
Запустите
topи изучите его интерфейс:Окно терминала top- Нажмите
P— сортировка по CPU. - Нажмите
M— сортировка по памяти. - Нажмите
1— показать загрузку по отдельным ядрам. - Нажмите
q— выход.
- Нажмите
-
Установите и запустите
htop(более удобный аналог):Окно терминала sudo apt install htophtopСравните интерфейсы
topиhtop. Какие преимущества уhtop? -
Просмотрите информацию о памяти и CPU:
Окно терминала free -huptimecat /proc/loadavgЧто означают три числа load average?
Часть 2. Управление процессами
Задание 2.1. Фоновые процессы
-
Запустите долгий процесс в фоне:
Окно терминала sleep 300 &echo "PID фонового процесса: $!" -
Просмотрите список фоновых задач:
Окно терминала jobs -l -
Запустите процесс на переднем плане и переведите в фон:
Окно терминала sleep 200# Нажмите Ctrl+Z (приостановка)bg # Возобновить в фонеjobsfg # Вернуть на передний план -
Запустите процесс, который переживёт закрытие терминала:
Окно терминала nohup sleep 600 &cat nohup.out
Задание 2.2. Сигналы
-
Запустите фоновый процесс и отправьте ему сигналы:
Окно терминала sleep 1000 &PID=$!echo "Запущен процесс $PID"# Отправить SIGTERM (мягкое завершение)kill $PID# или явно:kill -SIGTERM $PID# Проверить, жив ли процессps -p $PID -
Создайте «упорный» процесс и убейте его принудительно:
Окно терминала # Запустим процесс, игнорирующий SIGTERMbash -c 'trap "" SIGTERM; while true; do sleep 1; done' &PID=$!kill $PID # Не сработает (SIGTERM перехвачен)ps -p $PID # Процесс живkill -9 $PID # SIGKILL — нельзя перехватитьps -p $PID # Процесс завершён -
Отправьте сигнал
SIGUSR1и перехватите его:Окно терминала bash -c 'trap "echo Получен SIGUSR1!" SIGUSR1echo "Мой PID: $$"while true; do sleep 1; done' &PID=$!kill -SIGUSR1 $PID# В выводе появится "Получен SIGUSR1!"kill $PID
Задание 2.3. Приоритеты
-
Запустите процесс с пониженным приоритетом:
Окно терминала nice -n 10 sleep 300 &ps -o pid,ni,comm -p $! -
Измените приоритет работающего процесса:
Окно терминала sleep 300 &PID=$!renice 5 -p $PIDps -o pid,ni,comm -p $PID -
Попробуйте установить отрицательный nice (потребуется sudo):
Окно терминала sleep 300 &PID=$!sudo renice -5 -p $PIDps -o pid,ni,comm -p $PID
Часть 3. Каналы и IPC
Задание 3.1. Именованные каналы (FIFO)
-
Создайте именованный канал:
Окно терминала mkfifo /tmp/mypipels -la /tmp/mypipe # Обратите внимание на тип файла (p) -
Откройте два терминала. В первом:
Окно терминала echo "Привет из терминала 1!" > /tmp/mypipeВо втором:
Окно терминала cat < /tmp/mypipeОбратите внимание:
echoблокируется, пока кто-то не прочитает из канала. -
Удалите канал:
Окно терминала rm /tmp/mypipe
Задание 3.2. Трассировка системных вызовов
-
Проследите системные вызовы простой команды:
Окно терминала strace ls /tmp 2>&1 | head -30Найдите вызовы
openat,read,write,close. Что делает каждый? -
Проследите системные вызовы при создании процесса:
Окно терминала strace -f bash -c 'echo hello' 2>&1 | grep -E '(clone|exec|write)'Найдите вызовы
clone(аналог fork) иexecve. -
Подсчитайте количество каждого типа системных вызовов:
Окно терминала strace -c ls /tmp 2>&1
Часть 4. Bash-скрипты
Задание 4.1. Основы скриптов
-
Создайте файл
~/project/src/main/hello.sh:#!/bin/bash# ПеременныеNAME="Студент"COURSE="Операционные системы"echo "Привет, $NAME!"echo "Добро пожаловать на курс: $COURSE"echo "Текущая дата: $(date)"echo "Вы работаете на: $(hostname)"echo "Ваш пользователь: $(whoami)" -
Сделайте скрипт исполняемым и запустите:
Окно терминала chmod +x ~/project/src/main/hello.sh~/project/src/main/hello.sh
Задание 4.2. Аргументы и условия
Создайте скрипт ~/project/src/main/check_file.sh:
#!/bin/bash
# Проверка аргументовif [ $# -eq 0 ]; then echo "Использование: $0 <путь_к_файлу>" exit 1fi
FILE=$1
if [ -e "$FILE" ]; then echo "Файл '$FILE' существует."
if [ -f "$FILE" ]; then echo " Тип: обычный файл" echo " Размер: $(stat --format=%s "$FILE") байт" echo " Строк: $(wc -l < "$FILE")" elif [ -d "$FILE" ]; then echo " Тип: каталог" echo " Элементов: $(ls -1 "$FILE" | wc -l)" elif [ -L "$FILE" ]; then echo " Тип: символическая ссылка → $(readlink "$FILE")" fi
echo " Права: $(stat --format=%A "$FILE")" echo " Владелец: $(stat --format=%U "$FILE")"else echo "Файл '$FILE' не существует." exit 2fiПротестируйте скрипт на разных объектах:
chmod +x ~/project/src/main/check_file.sh~/project/src/main/check_file.sh /etc/passwd~/project/src/main/check_file.sh /tmp~/project/src/main/check_file.sh /nonexistentЗадание 4.3. Циклы и функции
Создайте скрипт ~/project/src/main/process_report.sh:
#!/bin/bash
# Функция вывода разделителяseparator() { echo "$(printf '=%.0s' {1..50})"}
# Функция подсчёта процессов пользователяcount_user_processes() { local user=$1 ps -u "$user" --no-headers | wc -l}
separatorecho "ОТЧЁТ О ПРОЦЕССАХ"echo "Дата: $(date)"separator
echo ""echo "Всего процессов: $(ps aux --no-headers | wc -l)"echo "Загрузка CPU: $(uptime | grep -oP 'load average: \K.*')"echo "Память:"free -h | grep Mem | awk '{printf " Всего: %s | Использовано: %s | Свободно: %s\n", $2, $3, $4}'
echo ""echo "Топ-5 процессов по CPU:"ps aux --sort=-%cpu --no-headers | head -5 | awk '{printf " PID: %-8s CPU: %-6s MEM: %-6s CMD: %s\n", $2, $3, $4, $11}'
echo ""echo "Топ-5 процессов по памяти:"ps aux --sort=-%mem --no-headers | head -5 | awk '{printf " PID: %-8s CPU: %-6s MEM: %-6s CMD: %s\n", $2, $3, $4, $11}'
echo ""echo "Процессы по пользователям:"for user in $(ps aux --no-headers | awk '{print $1}' | sort -u); do count=$(count_user_processes "$user") printf " %-15s %d процессов\n" "$user" "$count"done
separatorМини-проект: скрипт мониторинга системы
Напишите скрипт ~/project/src/main/monitor.sh, который:
- Принимает аргумент — интервал в секундах (по умолчанию 5).
- Каждые N секунд записывает в файл
~/project/logs/monitor.csvстроку:timestamp,cpu_usage,mem_total,mem_used,mem_percent,proc_count - При первом запуске создаёт заголовок CSV.
- Выводит на экран текущие показатели в удобном формате.
- По нажатию
Ctrl+C(сигнал SIGINT) выводит итоговую статистику:- Сколько замеров было сделано.
- Средняя загрузка CPU.
- Максимальное использование памяти.
- Время работы скрипта.
- Корректно завершается.
Подсказки:
- Загрузку CPU можно получить из
top -bn1 | grep "Cpu(s)"или из/proc/stat. - Информацию о памяти — из
free. - Для перехвата
Ctrl+Cиспользуйтеtrap. - Для подсчёта среднего используйте
awk.
Шаблон:
#!/bin/bash
INTERVAL=${1:-5}LOG_FILE=~/project/logs/monitor.csvCOUNT=0START_TIME=$(date +%s)
# Заголовок CSVecho "timestamp,cpu_usage,mem_total,mem_used,mem_percent,proc_count" > "$LOG_FILE"
# Обработчик Ctrl+Ccleanup() { echo "" echo "=== Итоги мониторинга ===" echo "Замеров: $COUNT" # TODO: вычислить среднюю загрузку CPU и макс. память ELAPSED=$(($(date +%s) - START_TIME)) echo "Время работы: ${ELAPSED} сек" exit 0}
trap cleanup SIGINT
# Основной циклwhile true; do # TODO: собрать метрики # TODO: записать в CSV # TODO: вывести на экран COUNT=$((COUNT + 1)) sleep "$INTERVAL"doneКонтрольные вопросы
- Чем процесс отличается от программы? Какую информацию содержит PCB?
- Какие состояния может иметь процесс в Linux? Что означают коды в столбце
STATкомандыps? - Чем
SIGTERMотличается отSIGKILL? Какой из них можно перехватить? - Что такое PID 1? Какую роль он играет в системе?
- Как работает механизм
fork()+exec()в Unix? Что такое Copy-on-Write? - Чем отличается фоновый процесс (
&) от процесса, запущенного черезnohup? - Что показывает
strace? Для чего он используется? - Объясните разницу между
niceиrenice. - Что такое именованный канал (FIFO)? Чем он отличается от обычного pipe (
|)? - Что такое load average? Как интерпретировать значения 0.5, 1.0, 4.0 на одноядерной и четырёхъядерной системе?