Почему
Одна из классических загадок Linux:
Куда пропало место?
▪️ Что считают du и df
Из-за этого их значения могут различаться.
▪️ Самая частая причина
Удалённый файл всё ещё открыт процессом.
Например:
Но если процесс продолжает писать в него, место останется занятым.
Найти такие файлы можно так:
▪️ Другие причины
Зарезервированные блоки ext4:
▪️ Быстрая диагностика
Если диск внезапно заполнился:
▪️ Почему это важно
На продакшн-серверах часто удаляют огромный лог в надежде освободить место. Но если процесс продолжает держать файл открытым, свободное пространство не появится, а приложение может вскоре упасть из-за нехватки диска.
BashTex📱 #scripts #du
du и df показывают разный размерОдна из классических загадок Linux:
df -h
Показывает:/dev/sda1 100%
Но если проверить содержимое файловой системы:du -sh /var
du -sh /home
du -sh /opt
Суммарный объём получается заметно меньше.Куда пропало место?
du подсчитывает размер файлов, которые видны в файловой системе.df показывает занятые блоки на уровне самой файловой системы.Из-за этого их значения могут различаться.
Удалённый файл всё ещё открыт процессом.
Например:
rm app.log
Файл исчез из каталога, поэтому du его больше не видит.Но если процесс продолжает писать в него, место останется занятым.
Найти такие файлы можно так:
lsof +L1
Пример вывода:java 1234 user 5w REG ... app.log (deleted)
Пока процесс не завершится или не закроет дескриптор, место не освободится.Зарезервированные блоки ext4:
tune2fs -l /dev/sda1 | grep Reserved
Смонтированные файловые системы внутри каталогов:mount | column -t
Или bind-монтирования, из-за которых данные учитываются неожиданным образом.Если диск внезапно заполнился:
df -h
lsof +L1
Во многих случаях проблема обнаруживается уже на втором шаге.На продакшн-серверах часто удаляют огромный лог в надежде освободить место. Но если процесс продолжает держать файл открытым, свободное пространство не появится, а приложение может вскоре упасть из-за нехватки диска.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Почему
Многие администраторы при зависшем процессе сразу используют:
▪️ Что делает SIGKILL
Сигнал
Процесс не может его перехватить, обработать или проигнорировать.
Ядро просто убивает его.
▪️ Что при этом не происходит
Процесс не успевает:
сохранить данные
закрыть файлы
завершить активные операции
удалить временные файлы
выполнить обработчики завершения
Например, база данных может не успеть корректно завершить транзакции.
▪️ Что использовать сначала
Обычный сигнал завершения:
Процесс получает запрос на завершение и может корректно освободить ресурсы.
▪️ Посмотреть, реагирует ли процесс
Отправляем SIGTERM:
▪️ Полезный приём
Для сервисов под systemd лучше использовать:
Только если сервис не реагирует, будет применено принудительное завершение.
▪️ Почему это важно
BashTex📱 #scripts #kill9
kill -9 - не лучший способ остановить процессМногие администраторы при зависшем процессе сразу используют:
kill -9 <PID>
Обычно это работает. Но далеко не всегда это правильное решение.Сигнал
-9 (SIGKILL) принудительно завершает процесс на уровне ядра.Процесс не может его перехватить, обработать или проигнорировать.
Ядро просто убивает его.
Процесс не успевает:
сохранить данные
закрыть файлы
завершить активные операции
удалить временные файлы
выполнить обработчики завершения
Например, база данных может не успеть корректно завершить транзакции.
Обычный сигнал завершения:
kill <PID>
илиkill -15 <PID>
Это SIGTERM.Процесс получает запрос на завершение и может корректно освободить ресурсы.
Отправляем SIGTERM:
kill -15 1234
Проверяем:ps -p 1234
Если процесс всё ещё работает спустя разумное время, тогда можно переходить к более жёстким мерам.Для сервисов под systemd лучше использовать:
systemctl stop myapp
systemd сам отправит нужные сигналы в правильном порядке и подождёт завершения процесса.Только если сервис не реагирует, будет применено принудительное завершение.
kill -9 часто помогает быстро решить проблему, но одновременно может создавать новые. Поэтому его лучше рассматривать как последний инструмент, когда процесс уже не отвечает на обычное завершение.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Проверка недавно созданных пользователей: UID, shell и следы активности
На сервере часто важно быстро понять, появлялись ли новые пользователи и насколько они “нормальные”.
Один из базовых источников -
▪️ Поиск пользователей с обычным UID диапазоном
Системные - ниже.
Смотрим shell:
▪️ Быстрый срез через lastlog
▪️ Проверка событий создания пользователей
▪️ Косвенная проверка “новизны”
Можно оценить свежесть через системные изменения:
▪️ Дополнительная проверка активности
▪️ Почему это важно
Новые пользователи с UID 1000+, нестандартным shell или отсутствием логинов — один из первых сигналов, который стоит проверять при аудите сервера.
BashTex📱 #scripts #du
На сервере часто важно быстро понять, появлялись ли новые пользователи и насколько они “нормальные”.
Один из базовых источников -
/etc/passwd, но там нет явной даты создания. Поэтому анализ строится через косвенные признаки.getent passwd | awk -F: '$3 >= 1000 {print $1, $3, $7}'
Обычно реальные пользователи находятся начиная с UID 1000. Системные - ниже.
Смотрим shell:
/bin/bash, /bin/zsh чаще у людей, /usr/sbin/nologin или /bin/false - сервисные аккаунты.lastlog -t 30
Показывает пользователей, которые логинились за последние 30 дней. Новые аккаунты без активности сразу заметны.journalctl _COMM=useradd --since "7 days ago"
или через auth лог:grep useradd /var/log/auth.log
Здесь видны факты создания аккаунтов и изменения групп.Можно оценить свежесть через системные изменения:
stat /etc/passwd
или изменения shadow:stat /etc/shadow
Если недавно был добавлен пользователь, эти файлы будут обновлены в тот же период.faillog -a
иlast
Позволяют понять, пытался ли пользователь входить в систему и с каких хостов.Новые пользователи с UID 1000+, нестандартным shell или отсутствием логинов — один из первых сигналов, который стоит проверять при аудите сервера.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Работа с дескрипторами файлов через
В Bash обычно работают только с stdin (0), stdout (1) и stderr (2). Но файловые дескрипторы на этом не заканчиваются - можно использовать FD 3, 4 и выше для более гибкого управления потоками.
▪️ Базовая идея
Каждый процесс имеет таблицу файловых дескрипторов:
▪️ Разделение логов
Классический приём - разделить обычный вывод и отладку:
stdout остаётся чистым
debug уходит в отдельный файл
▪️ Перенаправление команд через FD
Можно связать вывод команды с кастомным дескриптором:
Чтение:
▪️ Логирование через единый канал
Удобный паттерн - централизованный лог:
▪️ Почему это лучше обычного >> везде
единая точка управления логированием
проще отключать/перенаправлять вывод
можно динамически менять файл логов через
▪️ Закрытие дескрипторов
▪️ Где это реально используется
сложные Bash-скрипты с несколькими потоками данных
системы логирования без внешних библиотек
обработка нескольких входных источников одновременно
изоляция debug/production вывода
FD выше 2 - это недооценённый инструмент, который превращает Bash из набора команд в полноценную систему управления потоками.
BashTex📱 #scripts #linux
exec: FD 3, 4, логирование и контроль потоковВ Bash обычно работают только с stdin (0), stdout (1) и stderr (2). Но файловые дескрипторы на этом не заканчиваются - можно использовать FD 3, 4 и выше для более гибкого управления потоками.
Каждый процесс имеет таблицу файловых дескрипторов:
0 → stdin
1 → stdout
2 → stderr
Но можно открыть дополнительные:exec 3>debug.log
Теперь FD 3 пишет в файл debug.log.Классический приём - разделить обычный вывод и отладку:
echo "normal output"
echo "debug info" >&3
Результат:stdout остаётся чистым
debug уходит в отдельный файл
Можно связать вывод команды с кастомным дескриптором:
exec 4< input.txt
Теперь FD 4 читает файл как поток.Чтение:
read -u 4 line
echo "$line"
Удобный паттерн - централизованный лог:
exec 3>>/var/log/myapp.log
log() {
echo "$(date '+%F %T') $*" >&3
}
Теперь все логи идут через FD 3, без захламления stdout.единая точка управления логированием
проще отключать/перенаправлять вывод
можно динамически менять файл логов через
execexec 3>&-
FD освобождается, файл больше не удерживается процессом.сложные Bash-скрипты с несколькими потоками данных
системы логирования без внешних библиотек
обработка нескольких входных источников одновременно
изоляция debug/production вывода
FD выше 2 - это недооценённый инструмент, который превращает Bash из набора команд в полноценную систему управления потоками.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
Bash strict mode: что реально даёт set -euo pipefail и где он ломает логику
В bash часто добавляют так называемый "strict mode":
▪️ Что означает каждая опция
▪️ Что это реально улучшает
Без strict mode многие ошибки проглатываются:
Или:
будет явная ошибка, а не пустая строка.
▪️ pipefail: скрытая проблема пайп
Без него:
Возвращает код последней команды, даже если grep упал.
▪️ Где начинается проблема. Strict mode ломает сценарии, где ошибка - это нормальное состояние.
Пример:
Если совпадений нет, grep возвращает 1 и скрипт завершается, хотя это не ошибка логики.
▪️ Типичный workaround
Или:
Но это уже
▪️ ещё один частый кейс - test / if
Здесь grep
▪️ Итоговый баланс
Strict mode хорошо работает в:
• CI/CD
• одноразовых скриптах
• автоматизации без ветвлений
Но начинает мешать в:
• парсинге данных
• поиске (grep как логика)
• скриптах с ожидаемыми "ошибками как состоянием"
Это не универсальная защита, а переключатель модели поведения Bash-скрипта: от гибкого к строго детерминированному.
BashTex📱 #scripts #linux
В bash часто добавляют так называемый "strict mode":
set -euo pipefail
Идея простая - сделать скрипты более предсказуемыми и ловить ошибки раньше.-e - остановить скрипт при любой ошибке команды-u - ошибка при использовании неинициализированной переменной-o pipefail - пайп считается упавшим, если упала любая команда в цепочке
Без strict mode многие ошибки проглатываются:
rm file_not_exist
echo "continue"
Или:
echo "$UNDEFINED_VAR"
будет явная ошибка, а не пустая строка.
Без него:
cat file | grep ERROR | sort
Возвращает код последней команды, даже если grep упал.
Пример:
grep pattern file.txt
echo "done"
Если совпадений нет, grep возвращает 1 и скрипт завершается, хотя это не ошибка логики.
grep pattern file.txt || true
Или:
set +e
grep pattern file.txt
set -e
Но это уже
ручное управление поведением.
set -e
if grep pattern file.txt; then
echo "found"
fi
Здесь grep
может упасть, но в контексте if это нормальный контроль потока - и это не считается фатальной ошибкой.Strict mode хорошо работает в:
• CI/CD
• одноразовых скриптах
• автоматизации без ветвлений
Но начинает мешать в:
• парсинге данных
• поиске (grep как логика)
• скриптах с ожидаемыми "ошибками как состоянием"
Это не универсальная защита, а переключатель модели поведения Bash-скрипта: от гибкого к строго детерминированному.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
coproc на практике: двусторонний обмен данными с процессом
В bash обычно все сводится к pipe: команда - команда. Но классический пайп односторонний. Если нужен диалог с процессом в обе стороны - используется coproc.
▪️ Что такое coproc. Он запускает процесс и даёт два канала:
stdin - в процесс
stdout - из процесса
И все это без временных файлов и костылей с FIFO.
▪️ Базовый пример
Теперь у нас есть процесс калькулятора, с которым можно общаться.
Отправляем данные:
▪️ Как это устроено. После запуска bash создает массив:
Можно читать и писать независимо.
▪️ Реальный кейс: фоновый parser
Отправляем поток данных:
▪️ Почему это лучше pipe Pipe работает так:
Но:
• нет обратного канала
• процесс заканчивается сразу
• нельзя поддерживать состояние
coproc позволяет держать живой процесс и общаться с ним как с сервисом.
▪️ Важный момент. Процесс внутри coproc не перезапускается автоматически. Если он завершился - каналы перестают работать, и это нужно проверять вручную.
▪️ Где это реально полезно
• интерактивные CLI-инструменты (bc, python, sqlite3)
• долгоживущие парсеры (jq, awk, кастомные демоны)
• проксирование данных между процессами
• построение "мини-сервисов" прямо в Bash
coproc превращает bash из набора команд в примитивную систему IPC, где процессы начинают вести диалог, а не просто передавать поток данных в одну сторону.
BashTex📱 #bash #scripts
В bash обычно все сводится к pipe: команда - команда. Но классический пайп односторонний. Если нужен диалог с процессом в обе стороны - используется coproc.
stdin - в процесс
stdout - из процесса
И все это без временных файлов и костылей с FIFO.
coproc BC { bc -l; }
Теперь у нас есть процесс калькулятора, с которым можно общаться.
Отправляем данные:
echo "2+2" >&"${BC[1]}"
read result <&"${BC[0]}"
echo "$result"
${COPROC[0]} # stdout процесса
${COPROC[1]} # stdin процесса
Можно читать и писать независимо.
coproc JSON { jq -c '.name'; }
Отправляем поток данных:
echo '{"name":"test"}' >&"${JSON[1]}"
read out <&"${JSON[0]}"
echo "$out"
cmd1 | cmd2
Но:
• нет обратного канала
• процесс заканчивается сразу
• нельзя поддерживать состояние
coproc позволяет держать живой процесс и общаться с ним как с сервисом.
• интерактивные CLI-инструменты (bc, python, sqlite3)
• долгоживущие парсеры (jq, awk, кастомные демоны)
• проксирование данных между процессами
• построение "мини-сервисов" прямо в Bash
coproc превращает bash из набора команд в примитивную систему IPC, где процессы начинают вести диалог, а не просто передавать поток данных в одну сторону.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
nameref (
В Bash функции по умолчанию работают с копиями значений или с глобальными переменными. Но есть механизм, который позволяет имитировать “ссылки” -
▪️ Что такое nameref
▪️ Передача массива в функцию без копирования
Классическая проблема:
С
▪️ Модификация массива внутри функции
▪️ Где это особенно полезно
функции обработки конфигураций
парсинг JSON → массивы ключей/значений
работа с таблицами данных
построение библиотек на Bash без глобальных переменных
▪️ Важный момент
• значения
• выражения
• результаты команд
Только имя переменной.
▪️ Ограничения
нельзя безопасно переиспользовать ссылку на разные переменные в одном scope без переопределения
сложнее отлаживать (меняется оригинальный объект)
требует Bash 4.3+
▪️ Почему это важно
Без
BashTex📱 #scripts #linux
declare -n): ссылки на переменные и передача массивов в функцииВ Bash функции по умолчанию работают с копиями значений или с глобальными переменными. Но есть механизм, который позволяет имитировать “ссылки” -
nameref.declare -n создаёт ссылку на другую переменную:arr=(1 2 3)
declare -n ref=arr
ref[0]=999
echo "${arr[0]}"
Результат:999
ref не хранит данные - он указывает на arr.Классическая проблема:
func() {
local arr=("$@")
}
Это создаёт копию массива.С
nameref:func() {
local -n arr=$1
echo "${arr[0]}"
}
Вызов:data=(10 20 30)
func data
Функция работает с оригинальным массивом.func() {
local -n arr=$1
arr[1]=999
}
data=(10 20 30)
func data
echo "${data[@]}"
Результат:
10 999 30
функции обработки конфигураций
парсинг JSON → массивы ключей/значений
работа с таблицами данных
построение библиотек на Bash без глобальных переменных
nameref работает только с именами переменных:local -n ref=$1
Нельзя передавать:• значения
• выражения
• результаты команд
Только имя переменной.
нельзя безопасно переиспользовать ссылку на разные переменные в одном scope без переопределения
сложнее отлаживать (меняется оригинальный объект)
требует Bash 4.3+
Без
nameref Bash-функции либо копируют данные, либо используют глобальное состояние. declare -n даёт третий вариант — передачу по ссылке, что делает сложные скрипты заметно чище и ближе к языкам общего назначения.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Автоматическая реакция на OOM через systemd и cgroups: перезапуск и контроль памяти
OOM (Out Of Memory) - это не просто “закончилась память”. В Linux это механизм, при котором ядро начинает принудительно завершать процессы, чтобы система не упала целиком.
Проблема в том, что без контроля первым под нож часто попадает не тот процесс, который должен.
▪️ Как systemd влияет на OOM
systemd работает поверх cgroups и может задавать приоритеты “жертвенности” процессов:
▪️ Влияние на OOM Killer
Можно управлять приоритетом уничтожения:
▪️ Автоматический перезапуск после OOM
systemd может перезапускать сервис даже после убийства ядром:
▪️ Практический сценарий
Типичная ситуация:
• сервис разогнал память
• ядро убивает его через OOM
• systemd фиксирует падение
• запускает новый экземпляр
• cgroups не дают повторно выйти за лимит
▪️ Где начинается реальный контроль
Ключевой момент - сочетание:
• MemoryMax (жёсткий лимит)
• MemoryHigh (раннее давление)
• OOMScoreAdjust (приоритет убийства)
• Restart=on-failure (самовосстановление)
▪️ Почему это важно
Без cgroups OOM - это хаос: ядро выбирает жертву само.
С systemd это превращается в управляемую систему: процесс либо не доходит до OOM, либо корректно переживает его через перезапуск и ограничение ресурсов.
BashTex📱 #scripts #linux
OOM (Out Of Memory) - это не просто “закончилась память”. В Linux это механизм, при котором ядро начинает принудительно завершать процессы, чтобы система не упала целиком.
Проблема в том, что без контроля первым под нож часто попадает не тот процесс, который должен.
systemd работает поверх cgroups и может задавать приоритеты “жертвенности” процессов:
systemd-cgtop
Показывает, какие группы потребляют память.
▪️Контроль памяти на уровне unit
Можно ограничить сервис:
[Service]
MemoryMax=500M
Теперь процесс физически не сможет превысить лимит.
Дополнительно:
MemoryHigh=400M
Это мягкий порог - systemd начинает давить на процесс раньше, чем наступит OOM.Можно управлять приоритетом уничтожения:
OOMScoreAdjust=-500
или наоборот:
OOMScoreAdjust=500
Чем выше значение - тем выше шанс, что процесс будет убит первым.systemd может перезапускать сервис даже после убийства ядром:
[Service]
Restart=on-failure
RestartSec=2
Это работает и для OOM-kill, потому что процесс считается завершённым с ошибкой.Типичная ситуация:
• сервис разогнал память
• ядро убивает его через OOM
• systemd фиксирует падение
• запускает новый экземпляр
• cgroups не дают повторно выйти за лимит
Ключевой момент - сочетание:
• MemoryMax (жёсткий лимит)
• MemoryHigh (раннее давление)
• OOMScoreAdjust (приоритет убийства)
• Restart=on-failure (самовосстановление)
Без cgroups OOM - это хаос: ядро выбирает жертву само.
С systemd это превращается в управляемую систему: процесс либо не доходит до OOM, либо корректно переживает его через перезапуск и ограничение ресурсов.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Проверка файловых систем, смонтированных с опасными опциями
При аудите Linux обычно проверяют права доступа и SUID-биты. Но не менее важно посмотреть, как смонтированы файловые системы.
Если временный каталог или пользовательский раздел смонтирован с
▪️ Посмотреть все точки монтирования
Самый удобный способ:
▪️ На что обратить внимание
Опции монтирования:
•
•
•
Для каталогов вроде
▪️ Пример проверки
Более безопасный вариант:
▪️ Проверка через fstab
Чтобы убедиться, что настройки сохранятся после перезагрузки:
▪️ Почему это важно
Представьте, что злоумышленник смог записать файл в
Несколько минут на проверку параметров монтирования могут устранить целый класс потенциальных проблем ещё до того, как они будут использованы.
BashTex📱 #scripts #linux
При аудите Linux обычно проверяют права доступа и SUID-биты. Но не менее важно посмотреть, как смонтированы файловые системы.
Если временный каталог или пользовательский раздел смонтирован с
exec, suid или dev, это может значительно расширить поверхность атаки.Самый удобный способ:
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
Или классический вариант:mount
Опции монтирования:
•
exec - разрешает запуск исполняемых файлов.•
suid - позволяет работать SUID/SGID-битам.•
dev - разрешает использование файлов устройств.Для каталогов вроде
/tmp, /var/tmp или /dev/shm обычно безопаснее использовать противоположные опции:noexec,nosuid,nodev
findmnt -no TARGET,OPTIONS /tmp
Если вывод содержит:rw,relatime
значит ограничения отсутствуют.Более безопасный вариант:
rw,nosuid,nodev,noexec
Чтобы убедиться, что настройки сохранятся после перезагрузки:
grep -vE '^\s*#|^$' /etc/fstab
Ищите разделы, где для временных или пользовательских файловых систем не заданы защитные опции.Представьте, что злоумышленник смог записать файл в
/tmp. Если раздел смонтирован с exec, его можно сразу запустить. Если ещё и разрешён suid или dev, последствия могут быть значительно серьёзнее.Несколько минут на проверку параметров монтирования могут устранить целый класс потенциальных проблем ещё до того, как они будут использованы.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Когда переменные пропадают
Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.
▪️ Что такое subshell. Subshell - это дочерний процесс bash. Он получает копию переменных, но изменения не возвращаются назад. Создается, например, здесь:
или в пайпах:
▪️ Классическая проблема
Результат: 0
Почему? Цикл while выполняется в subshell.
▪️ Правильный вариант
Результат: 3
Теперь цикл работает в текущем shell.
▪️ Ещё пример
Результат: 1
Изменение потерялось.
▪️ Когда это полезно. Subshell - это не баг, а инструмент. Например:
внутри меняем каталог, а снаружи остаемся там же
BashTex📱 #scripts
Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.
( command )
или в пайпах:
command | while read ...
count=0
echo -e "a\nb\nc" | while read -r line; do
((count++))
done
echo "$count"
Результат: 0
Почему? Цикл while выполняется в subshell.
count=0
while read -r line; do
((count++))
done < <(echo -e "a\nb\nc")
echo "$count"
Результат: 3
Теперь цикл работает в текущем shell.
x=1
( x=5 )
echo "$x"
Результат: 1
Изменение потерялось.
( cd /tmp && ls )
внутри меняем каталог, а снаружи остаемся там же
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5