Контроль роста логов systemd по сервисам
Когда
1️⃣ Сколько логов пишет сервис. Пример для nginx:
Получаем объем логов за час (в байтах).
2️⃣ Быстрый топ шумных сервисов
Результат:
Сразу видно, кто генерирует больше всего логов.
3️⃣ Контроль роста. Сохраняем текущее состояние:
Через время:
4️⃣ Скрипт
BashTex📱 #systemd #logs
Когда
/var/log начинает раздуваться, виноват почти всегда один-два шумных сервиса. Но в journald нет привычных файлов - значит нужно считать по-другому. Значит будем брать сервис, считать объем его логов и сравниваем во времени.
journalctl -u nginx --since "1 hour ago" | wc -c
Получаем объем логов за час (в байтах).
systemctl list-units --type=service --no-legend | awk '{print $1}' |
while read -r svc; do
size=$(journalctl -u "$svc" --since "1 hour ago" 2>/dev/null | wc -c)
echo "$size $svc"
done | sort -nr | head
Результат:
12345678 docker.service
9876543 nginx.service
1234567 ssh.service
Сразу видно, кто генерирует больше всего логов.
journalctl -u nginx --since "1 hour ago" | wc -c > /tmp/nginx.size
Через время:
old=$(cat /tmp/nginx.size)
new=$(journalctl -u nginx --since "1 hour ago" | wc -c)
echo "Рост: $((new - old)) байт"
#!/usr/bin/env bash
SINCE="10 min ago"
THRESHOLD=1000000 # 1 MB
systemctl list-units --type=service --no-legend | awk '{print $1}' |
while read -r svc; do
size=$(journalctl -u "$svc" --since "$SINCE" 2>/dev/null | wc -c)
if (( size > THRESHOLD )); then
echo "ALERT: $svc → $size bytes за $SINCE"
fi
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Работа с сигналами: SIGTERM, SIGINT, SIGHUP
Любой процесс в linux можно остановить сигналом. Если скрипт их не обрабатывает - он просто умирает, иногда оставляя: временные файлы, lock-файлы или незавершённые операции
▪️ Основные сигналы
SIGINT - (2) -
Остановка пользователем
SIGTERM (15) - вежливое завершение -
Дает процессу шанс корректно завершиться.
SIGHUP (1) - перечитай конфиг
часто используется для reload
▪️ Обработка сигналов через trap
Теперь скрипт не просто падает, а выполняет cleanup.
▪️ Пример cleanup
▪️ Полный пример
Теперь:
скрипт не оставляет мусор
Не все сигналы можно перехватить. Нельзя поймать: SIGKILL (9)
Если прилетит
BashTex📱 #scripts #utils
Любой процесс в linux можно остановить сигналом. Если скрипт их не обрабатывает - он просто умирает, иногда оставляя: временные файлы, lock-файлы или незавершённые операции
SIGINT - (2) -
Ctrl+CОстановка пользователем
SIGTERM (15) - вежливое завершение -
systemctl stop / killДает процессу шанс корректно завершиться.
SIGHUP (1) - перечитай конфиг
часто используется для reload
trap 'echo "Получен SIGINT"; cleanup; exit 1' INT
trap 'echo "Получен SIGTERM"; cleanup; exit 0' TERM
Теперь скрипт не просто падает, а выполняет cleanup.
cleanup() {
echo "Чистка..."
rm -f /tmp/my.lock
}
#!/usr/bin/env bash
LOCK=/tmp/job.lock
touch "$LOCK"
cleanup() {
echo "Удаляю lock"
rm -f "$LOCK"
}
trap cleanup EXIT
trap 'echo "SIGINT"; exit 1' INT
trap 'echo "SIGTERM"; exit 0' TERM
while true; do
echo "Работаю..."
sleep 2
done
Теперь:
Ctrl+C - корректное завершениеkill - cleanup выполняетсяскрипт не оставляет мусор
Не все сигналы можно перехватить. Нельзя поймать: SIGKILL (9)
Если прилетит
kill -9 - все, без cleanup.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4
Когда переменные пропадают
Одна из частых ловушек в 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
👍6
Файлы удалены, а место не освободилось
Классическая ситуация: удалили большой лог, df все еще показывает, что диск забит.
Ответ: файл удален из файловой системы, но процесс всё ещё держит его открытым.
▪️ Почему так происходит
В linux файл удаляется не сразу. Если процесс держит дескриптор: файл исчезает из каталога, но данные остаются на диске пока процесс не закроет файл
▪️ Как найти такие файлы
Пример вывода:
Это значит: файл удален, но процесс nginx все еще его держит
▪️ Найти самые тяжелые
Так можно быстро увидеть, кто реально съедает место.
▪️ Что делать
Вариант 1 - перезапустить сервис
Процесс закроет файл и место освободится.
Вариант 2 - убить процесс
(если можно безопасно остановить)
Вариант 3 - обнулить файл через
Где:
1234 - PID
10 - дескриптор из lsof
Это освободит место без перезапуска процесса.
BashTex📱 #storage
Классическая ситуация: удалили большой лог, df все еще показывает, что диск забит.
Ответ: файл удален из файловой системы, но процесс всё ещё держит его открытым.
В linux файл удаляется не сразу. Если процесс держит дескриптор: файл исчезает из каталога, но данные остаются на диске пока процесс не закроет файл
lsof | grep deleted
Пример вывода:
nginx 1234 user 10w REG ... /var/log/nginx/access.log (deleted)
Это значит: файл удален, но процесс nginx все еще его держит
lsof -nP | grep deleted | sort -k7 -nr | head
Так можно быстро увидеть, кто реально съедает место.
Вариант 1 - перезапустить сервис
systemctl restart nginx
Процесс закроет файл и место освободится.
Вариант 2 - убить процесс
kill 1234
(если можно безопасно остановить)
Вариант 3 - обнулить файл через
/proc
: > /proc/1234/fd/10
Где:
1234 - PID
10 - дескриптор из lsof
Это освободит место без перезапуска процесса.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Почему while read ломается в пайпах
Классическая ловушка Bash:
Ожидание: увидим количество строк.
Реальность: 0.
▪️ Что произошло
Когда while read стоит справа от пайпа, цикл часто выполняется в subshell - дочернем процессе. То есть переменная count меняется не в текущем shell, а в его копии. После окончания цикла изменения исчезают.
▪️ Как делать правильно. Вариант 1: редирект файла вместо pipe
Теперь цикл работает в текущем shell, и count сохраняется.
Вариант 2: process substitution. Если источник - команда, а не файл:
▪️ Почему это важно
Ломаются не только счетчики. Точно так же исчезают:, массивы, флаги, накопленные строки и любые переменные, измененные внутри цикла
BashTex📱 #bash
Классическая ловушка Bash:
count=0
cat file.txt | while read -r line; do
((count++))
done
echo "$count"
Ожидание: увидим количество строк.
Реальность: 0.
Когда while read стоит справа от пайпа, цикл часто выполняется в subshell - дочернем процессе. То есть переменная count меняется не в текущем shell, а в его копии. После окончания цикла изменения исчезают.
count=0
while IFS= read -r line; do
((count++))
done < file.txt
echo "$count"
Теперь цикл работает в текущем shell, и count сохраняется.
Вариант 2: process substitution. Если источник - команда, а не файл:
count=0
while IFS= read -r line; do
((count++))
done < <(grep ERROR app.log)
echo "$count"
<(...) подставляет вывод команды как файл, без subshell-проблемы в самом цикле.Ломаются не только счетчики. Точно так же исчезают:, массивы, флаги, накопленные строки и любые переменные, измененные внутри цикла
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Как найти процессы, которые активно пишут на диск
1️⃣ iotop - самый быстрый способ
Ключ
Для вывода без интерактивного режима:
Смотрите на колонки: DISK WRITE и COMMAND
2️⃣ pidstat - запись по процессам
Показывает дисковую активность процессов каждую секунду. Главная колонка: kB_wr/s. Она показывает скорость записи на диск. Пример:
3️⃣ Проверка через /proc. У каждого процесса есть файл:
Посмотреть статистику:
Ищем строку: write_bytes: Она показывает, сколько байт процесс записал с момента запуска.
Быстрый топ процессов по записи:
4️⃣ Какие файлы пишет процесс
Например:
Так можно понять, какие файлы открыты у подозрительного процесса.
5️⃣ Небольшая итоговая шпаргалка
Кто пишет на диск прямо сейчас.
Скорость чтения/записи по процессам.
I/O-статистика процесса.
Какие файлы открыл процесс.
BashTex📱 #storage
sudo iotop -o
Ключ
-o показывает только процессы с активным I/O.Для вывода без интерактивного режима:
sudo iotop -o -b -n 5
-b - batch mode-n 5 - 5 обновлений и выходСмотрите на колонки: DISK WRITE и COMMAND
pidstat -d 1
Показывает дисковую активность процессов каждую секунду. Главная колонка: kB_wr/s. Она показывает скорость записи на диск. Пример:
PID kB_rd/s kB_wr/s Command
1245 0.00 820.00 rsyslogd
2178 0.00 4096.00 mysqld
/proc/<PID>/io
Посмотреть статистику:
sudo cat /proc/<PID>/io
Ищем строку: write_bytes: Она показывает, сколько байт процесс записал с момента запуска.
Быстрый топ процессов по записи:
for pid in /proc/[0-9]*; do
[[ -r "$pid/io" ]] || continue
wb=$(awk '/write_bytes/ {print $2}' "$pid/io" 2>/dev/null)
cmd=$(cat "$pid/comm" 2>/dev/null)
[[ "$wb" -gt 0 ]] && echo "$wb PID=${pid##*/} $cmd"
done | sort -nr | head
sudo lsof -p <PID>
Например:
sudo lsof -p 2178
Так можно понять, какие файлы открыты у подозрительного процесса.
sudo iotop -o
Кто пишет на диск прямо сейчас.
pidstat -d 1
Скорость чтения/записи по процессам.
sudo cat /proc/<PID>/io
I/O-статистика процесса.
sudo lsof -p <PID>
Какие файлы открыл процесс.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Скрипт проверки зависших mount
Иногда сервер начинает странно тормозить: команда
Проверить это можно через связку: timeout + stat. Можно выполнить stat для точки монтирования, но ограничить время ожидания.
▪️ Пример ручной проверки
Если ФС отвечает - увидим информацию о каталоге. Если команда зависла и была остановлена по таймауту - mount подозрительный.
🛠 Скрипт проверки всех mount
Сохраняем:
Делаем исполняемым:
Запускаем:
Пример вывода
🛠 Также можно проверять только сетевые ФС
Такой вариант удобнее для серверов, где много локальных mount.
⚠️ stat может зависнуть, если ядро ждет ответ от удаленного хранилища. Поэтому мы оборачиваем его в timeout. Без timeout ваш скрипт сам может зависнуть на проблемной точке монтирования.
▪️ Быстрая проверка одной строкой
BashTex📱 #mount #script
Иногда сервер начинает странно тормозить: команда
df -h зависает, ls не отвечает, а проблема оказывается в примонтированной NFS/SMB/сетевой ФС. Причина простая: mount есть, но I/O к нему не отвечает.Проверить это можно через связку: timeout + stat. Можно выполнить stat для точки монтирования, но ограничить время ожидания.
timeout 3 stat /mnt/backup
Если ФС отвечает - увидим информацию о каталоге. Если команда зависла и была остановлена по таймауту - mount подозрительный.
#!/usr/bin/env bash
TIMEOUT=3
findmnt -rn -o TARGET | while read -r mountpoint; do
if timeout "$TIMEOUT" stat "$mountpoint" >/dev/null 2>&1; then
echo "OK: $mountpoint"
else
echo "HANG: $mountpoint"
fi
done
Сохраняем:
nano check-mounts.sh
Делаем исполняемым:
chmod +x check-mounts.sh
Запускаем:
sudo ./check-mounts.sh
Пример вывода
OK: /
OK: /boot
OK: /home
HANG: /mnt/backup
HANG: /mnt/nfs-share
#!/usr/bin/env bash
TIMEOUT=3
findmnt -rn -t nfs,nfs4,cifs,smb3 -o TARGET | while read -r mountpoint; do
if timeout "$TIMEOUT" stat "$mountpoint" >/dev/null 2>&1; then
echo "OK: $mountpoint"
else
echo "HANG: $mountpoint"
fi
done
Такой вариант удобнее для серверов, где много локальных mount.
findmnt -rn -o TARGET | while read -r mp; do
timeout 3 stat "$mp" >/dev/null 2>&1 \
&& echo "OK: $mp" \
|| echo "HANG: $mp"
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Please open Telegram to view this post
VIEW IN TELEGRAM
😁13
systemd.path: запуск действия при изменении файла
Многие задачи автоматизации до сих пор решают через бесконечные циклы:
▪️ Что есть лучше
В systemd существует специальный тип юнитов —
Он использует inotify и реагирует на реальные изменения файлов или директорий, а не занимается постоянным опросом.
Пример: нужно перезапускать сервис после изменения конфигурации.
Создаем path-юнит:
▪️ Что умеет отслеживать
Не только изменение файла:
▪️ Почему это удобно
Вместо собственных демонов, cron и циклов с
BashTex📱 #bash
Многие задачи автоматизации до сих пор решают через бесконечные циклы:
while true; do
if [ -f /tmp/reload ]; then
systemctl restart myapp
rm /tmp/reload
fi
sleep 5
done
Работает, но процесс постоянно висит в памяти и каждые несколько секунд проверяет состояние файловой системы.В systemd существует специальный тип юнитов —
.path.Он использует inotify и реагирует на реальные изменения файлов или директорий, а не занимается постоянным опросом.
Пример: нужно перезапускать сервис после изменения конфигурации.
Создаем path-юнит:
[Path]
PathModified=/etc/myapp/config.yml
[Install]
WantedBy=multi-user.target
И связанный сервис:
[Service]
Type=oneshot
ExecStart=/bin/systemctl restart myapp.service
Активируем:
systemctl daemon-reload
systemctl enable --now myapp.path
Теперь изменение файла автоматически вызовет запуск сервиса.Не только изменение файла:
PathExists=/tmp/file
PathChanged=/var/log/app.log
DirectoryNotEmpty=/var/spool/tasks
Например, можно запускать обработчик сразу после появления нового файла в директории или при заполнении очереди задач.Вместо собственных демонов, cron и циклов с
sleep получаем событийную модель: пока ничего не происходит - не расходуются ресурсы. Как только происходит нужное событие - systemd запускает действие.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
flock: защита от повторного запуска скрипта
Одна из самых неприятных проблем в автоматизации - случайный запуск нескольких копий одного скрипта.
Например, cron запускает задачу каждые 5 минут, но одна из прошлых итераций ещё не завершилась.
В результате появляются дублирующиеся процессы, конфликты при работе с файлами и непредсказуемые ошибки.
▪️ Типичная ошибка
Допустим, скрипт выполняется 10 минут, а cron запускает его каждые 5:
▪️ Решение через flock
Самый простой вариант - добавить блокировку:
Ключ
▪️ Использование внутри скрипта
Можно защитить сам скрипт независимо от способа запуска:
▪️ Чем лучше PID-файлов
Многие делают так:
▪️ Где особенно полезно
Бэкапы, синхронизация файлов, обработка очередей, обновление данных, cron-задачи и любые скрипты, которые нельзя запускать параллельно.
BashTex📱 #scripts #flock
Одна из самых неприятных проблем в автоматизации - случайный запуск нескольких копий одного скрипта.
Например, cron запускает задачу каждые 5 минут, но одна из прошлых итераций ещё не завершилась.
В результате появляются дублирующиеся процессы, конфликты при работе с файлами и непредсказуемые ошибки.
Допустим, скрипт выполняется 10 минут, а cron запускает его каждые 5:
*/5 * * * * /opt/backup.sh
Через некоторое время одновременно будут работать сразу несколько экземпляров.Самый простой вариант - добавить блокировку:
flock -n /tmp/backup.lock /opt/backup.sh
Если lock-файл уже занят другим процессом, новая копия просто не запустится.Ключ
-n означает “не ждать освобождения блокировки”.Можно защитить сам скрипт независимо от способа запуска:
exec 200>/var/run/myjob.lock
flock -n 200 || {
echo "Already running"
exit 1
}
Теперь второй экземпляр завершится сразу после старта.Многие делают так:
echo $$ > /tmp/script.pid
Но после аварийного завершения PID-файл может остаться, а PID уже будет принадлежать другому процессу.flock работает через файловые дескрипторы ядра и автоматически освобождает блокировку при завершении процесса.Бэкапы, синхронизация файлов, обработка очередей, обновление данных, cron-задачи и любые скрипты, которые нельзя запускать параллельно.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
PIPESTATUS: как узнать, где именно сломался пайп
Большинство администраторов знают про
Посмотрим на пример:
Если
▪️ Решение - PIPESTATUS
После выполнения пайпа Bash сохраняет коды возврата всех его команд в массиве
▪️ Проверка конкретного этапа
Можно обратиться к нужному элементу массива:
▪️ А что насчёт pipefail?
Многие включают:
Но
Для диагностики всё равно пригодится
▪️ Почему это важно
Если в скрипте есть длинные цепочки из
BashTex📱 #scripts #pipestatus
Большинство администраторов знают про
$?, но при работе с пайпами он может вводить в заблуждение.Посмотрим на пример:
grep ERROR app.log | sort | uniq
echo $?
Если пайп состоит из нескольких команд, $? покажет код возврата только последней из них.Если
grep завершился с ошибкой, а uniq отработал успешно, вы увидите:0
Хотя одна из команд фактически провалилась.После выполнения пайпа Bash сохраняет коды возврата всех его команд в массиве
PIPESTATUS:grep ERROR app.log | sort | uniq
echo "${PIPESTATUS[@]}"
Результат может выглядеть так:2 0 0
Здесь видно, что ошибка произошла именно в grep.Можно обратиться к нужному элементу массива:
grep ERROR app.log | sort | uniq
echo "${PIPESTATUS[0]}"
Проверяем первую команду в цепочке.echo "${PIPESTATUS[1]}"
Проверяем вторую.Многие включают:
set -o pipefail
Это полезно — теперь пайп вернёт ошибку, если упала любая команда внутри него.Но
pipefail не показывает, какой именно этап завершился неудачно.Для диагностики всё равно пригодится
PIPESTATUS.Если в скрипте есть длинные цепочки из
grep, awk, sed, jq, sort и других утилит, обычный $? может скрыть проблему. PIPESTATUS позволяет быстро понять, где именно произошёл сбой.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Почему журналы journald могут неожиданно заполнить диск
На сервере закончилось место, а в
Часто виновником оказывается journald.
▪️ Где хранятся логи
Проверить объём журналов можно одной командой:
▪️ Посмотреть самые “тяжёлые” журналы
Узнать, сколько данных записывается за последние сутки:
▪️ Как очистить старые журналы
Оставить только последние 500 МБ:
▪️ Ограничение роста журналов
Настройки находятся в:
▪️ Почему это важно
Когда приложение начинает писать ошибки в цикле, journald может вырасти до нескольких гигабайт за считанные часы. Если заранее не настроить лимиты, одна неудачная конфигурация способна оставить сервер без свободного места.
BashTex📱 #scripts #systemd
На сервере закончилось место, а в
/var/log ничего подозрительного нет?Часто виновником оказывается journald.
Проверить объём журналов можно одной командой:
journalctl --disk-usage
Например:Archived and active journals take up 2.8G on disk.
На серверах с большим количеством сервисов объём может расти довольно быстро.Узнать, сколько данных записывается за последние сутки:
journalctl --since yesterday | wc -l
А если какой-то сервис генерирует тысячи сообщений в минуту:journalctl -u myapp.service
Обычно проблема находится довольно быстро.Оставить только последние 500 МБ:
journalctl --vacuum-size=500M
Или удалить записи старше 14 дней:journalctl --vacuum-time=14d
Очистка происходит без остановки journald.Настройки находятся в:
/etc/systemd/journald.conf
Например:SystemMaxUse=1G
SystemKeepFree=2G
После изменения конфигурации:systemctl restart systemd-journald
Когда приложение начинает писать ошибки в цикле, journald может вырасти до нескольких гигабайт за считанные часы. Если заранее не настроить лимиты, одна неудачная конфигурация способна оставить сервер без свободного места.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
tmpfiles.d: автоматическое создание и очистка директорий без cron
На многих серверах можно встретить скрипты, которые создают нужные каталоги при загрузке системы или периодически чистят временные файлы через cron.
Хотя systemd умеет делать это самостоятельно.
▪️ Что такое tmpfiles.d
Механизм
Конфигурации обычно находятся здесь:
▪️ Создание каталога при старте
Допустим, приложению нужен каталог для кэша:
После применения:
▪️ Автоматическая очистка
Удалять файлы старше 7 дней:
Проверить правила можно так:
▪️ Где это полезно
Кэш приложений, временные выгрузки, очереди обработки файлов, каталоги с отчётами и любые данные, которые должны жить ограниченное время.
▪️ Почему это удобнее cron
Вместо отдельных скриптов и задач в планировщике вся логика хранения описывается одной строкой конфигурации. Создание, права доступа и очистка управляются стандартными средствами системы.
BashTex📱 #scripts #tmpfiles
На многих серверах можно встретить скрипты, которые создают нужные каталоги при загрузке системы или периодически чистят временные файлы через cron.
Хотя systemd умеет делать это самостоятельно.
Механизм
tmpfiles.d позволяет создавать каталоги, менять права доступа, владельцев и автоматически удалять старые файлы по заданным правилам.Конфигурации обычно находятся здесь:
/etc/tmpfiles.d/
/usr/lib/tmpfiles.d/
Допустим, приложению нужен каталог для кэша:
d /var/cache/myapp 0755 myapp myapp -
Где:d — создать директорию0755 — права доступаmyapp myapp — владелец и группаПосле применения:
systemd-tmpfiles --create
Каталог появится автоматически.Удалять файлы старше 7 дней:
D /var/tmp/myapp 0755 myapp myapp 7d
Теперь systemd будет очищать содержимое каталога согласно политике хранения.Проверить правила можно так:
systemd-tmpfiles --clean
Кэш приложений, временные выгрузки, очереди обработки файлов, каталоги с отчётами и любые данные, которые должны жить ограниченное время.
Вместо отдельных скриптов и задач в планировщике вся логика хранения описывается одной строкой конфигурации. Создание, права доступа и очистка управляются стандартными средствами системы.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Почему
Одна из классических загадок 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