Автоматическая ротация кастомных логов без logrotate
Не все логи живут в /var/log. Самописные сервисы часто пишут сюда:
Реализуем для них контролируемую ротацию на bash.
💚 Задача
архивировать логи старше N дней;
удалять архивы старше M дней;
не ломать активный файл;
не удалять то, что еще пишется.
1️⃣ Поиск логов старше N дней
⚠️
2️⃣ Архивирование с датой. Добавим gzip и текущую дату:
Здесь важно:
Никаких
3️⃣ Защита от удаления активного лога. Если сервис продолжает писать в файл, удалять его напрямую нельзя. Проверка через lsof:
Альтернатива: ротировать только логи, которые не менялись X часов:
4️⃣ Удаление старых архивов. Храним архивы 30 дней:
Лучше сначала проверить:
Только потом добавлять
5️⃣ Безопасный вариант с flock (чтобы не запустить дважды)
Теперь крон не создаст гонку.
▪️ Пример запуска через cron
BashTex📱 #bash #utils
Не все логи живут в /var/log. Самописные сервисы часто пишут сюда:
/opt/app/logs/
/srv/project/log/
/data/custom/*.log
Реализуем для них контролируемую ротацию на bash.
архивировать логи старше N дней;
удалять архивы старше M дней;
не ломать активный файл;
не удалять то, что еще пишется.
LOG_DIR="/opt/app/logs"
DAYS=7
find "$LOG_DIR" -type f -name "*.log" -mtime +$DAYS
-mtime +7 - старше 7 дней.mtime - это время последнего изменения.
ARCHIVE_DIR="/opt/app/archive"
mkdir -p "$ARCHIVE_DIR"
find "$LOG_DIR" -type f -name "*.log" -mtime +7 -print0 |
while IFS= read -r -d '' file; do
base=$(basename "$file")
gzip -c "$file" > "$ARCHIVE_DIR/${base}_$(date +%F).gz" && rm -f "$file"
done
Здесь важно:
-print0 + read -d '' - безопасно для пробеловgzip -c - сначала создаем архив&& rm - удаляем только если архив созданНикаких
rm до успешного gzip.
if lsof "$file" >/dev/null 2>&1; then
echo "Файл используется, пропускаем: $file"
continue
fi
Альтернатива: ротировать только логи, которые не менялись X часов:
-mmin +1440
find "$ARCHIVE_DIR" -type f -name "*.gz" -mtime +30 -delete
Лучше сначала проверить:
find "$ARCHIVE_DIR" -type f -mtime +30 -print
Только потом добавлять
-delete.
(
flock -n 200 || exit 1
# код ротации здесь
) 200>/var/lock/custom-log-rotate.lock
Теперь крон не создаст гонку.
0 3 * * * /usr/local/bin/custom_rotate.sh
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Проверка, какие команды доступны через sudo
Перед тем как что-то ломать или усиливать безопасность, полезно понять: что именно пользователь может запускать через sudo.
▪️ Базовая проверка
Показывает:
от какого пользователя можно выполнять команды
какие команды разрешены
есть ли NOPASSWD
Минус: в выводе много мусора.
▪️ Убираем лишнее. Только команды:
Или короче:
▪️ Быстро найти опасные права
Команды с NOPASSWD
Полный доступ (ALL)
Запуск shell’ов
▪️ Проверка другого пользователя (root)
BashTex📱 #bash
Перед тем как что-то ломать или усиливать безопасность, полезно понять: что именно пользователь может запускать через sudo.
sudo -l
Показывает:
от какого пользователя можно выполнять команды
какие команды разрешены
есть ли NOPASSWD
Минус: в выводе много мусора.
sudo -l | sed -n '/may run the following commands/,/^$/p'
Или короче:
sudo -l | grep -E '^\s*\('
Команды с NOPASSWD
sudo -l | grep NOPASSWD
Полный доступ (ALL)
sudo -l | grep '(ALL)'
Запуск shell’ов
sudo -l | grep -E 'bash|sh|zsh'
sudo -l -U username
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17
Ограничение времени выполнения команды
Иногда команда зависает навсегда: сетевой запрос, бэкап, скрипт.
▪️ Базовое использование
Если команда не завершилась за 5 секунд, то она будет остановлена.
Поддерживаемые единицы: 5s 2m 1h
▪️ В скриптах и cron. Пример с curl:
В cron это особенно важно т.к зависшая задача может копиться часами.
▪️ Проверка результата
Код 124 означает, что команда была прервана по таймауту.
▪️ Жесткое завершение
По умолчанию timeout шлёт SIGTERM.
Если процесс игнорирует его:
10s - мягкое завершение
+2s - принудительный SIGKILL
BashTex📱 #bash #utils
Иногда команда зависает навсегда: сетевой запрос, бэкап, скрипт.
timeout - это простой способ не дать ей убить автоматизацию.
timeout 5s command
Если команда не завершилась за 5 секунд, то она будет остановлена.
Поддерживаемые единицы: 5s 2m 1h
timeout 10s curl https://bashtex.com
В cron это особенно важно т.к зависшая задача может копиться часами.
timeout 5s long_task
case $? in
0) echo "OK" ;;
124) echo "Timeout" ;;
*) echo "Ошибка" ;;
esac
Код 124 означает, что команда была прервана по таймауту.
По умолчанию timeout шлёт SIGTERM.
Если процесс игнорирует его:
timeout -k 2s 10s command
10s - мягкое завершение
+2s - принудительный SIGKILL
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проверка: существует ли файл, каталог или ссылка
В bash не нужно городить ls | grep. Для проверок есть встроенные тесты, более быстрые и надежные.
▪️ Обычный файл -
Истина, если: файл есть и это не каталог
▪️ Каталог -
Полезно перед: копированием, cd или очисткой директорий
▪️ Символическая ссылка -
Работает даже если ссылка битая.
▪️ Просто что-то существует -
Файл, каталог, ссылка - все подряд.
▪️ Шпаргалка
BashTex📱 #bash #utils
В bash не нужно городить ls | grep. Для проверок есть встроенные тесты, более быстрые и надежные.
-f
[ -f file.txt ] && echo "Файл существует"
Истина, если: файл есть и это не каталог
-d
[ -d /etc/nginx ] && echo "Каталог существует"
Полезно перед: копированием, cd или очисткой директорий
-L
[ -L /usr/bin/python ] && echo "Это symlink"
Работает даже если ссылка битая.
-e
[ -e path ] || echo "Ничего нет"
Файл, каталог, ссылка - все подряд.
-fобычный файл-dкаталог-Lsymlink-eсуществует
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Захват вывода команды в переменную
Есть два способа сохранить вывод команды в переменную. Формально оба работают, но один из них устарел.
▪️ Правильный способ
Плюсы:
легко читать
можно вкладывать команды
меньше сюрпризов с экранированием
▪️ Устаревший способ
Минусы:
плохо читается
сложно экранировать
вложенность превращается в ад
▪️ Почему backticks ломают скрипты
`
ошибки трудно отлаживать
в больших скриптах быстро становится нечитаемо
▪️ Общая ловушка: переносы строк. Оба способа схлопывают переводы строк в пробелы:
Если важны строки:
BashTex📱 #bash #utils
Есть два способа сохранить вывод команды в переменную. Формально оба работают, но один из них устарел.
files=$(ls /etc)
Плюсы:
легко читать
можно вкладывать команды
меньше сюрпризов с экранированием
count=$(wc -l < file.txt)
files=`ls /etc
Минусы:
плохо читается
сложно экранировать
вложенность превращается в ад
# выглядит ужасно и ломается
result=`echo \`date\``
`
конфликтует с кавычкамиошибки трудно отлаживать
в больших скриптах быстро становится нечитаемо
list=$(cat file)
Если важны строки:
mapfile -t list < file
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Работа с массивами
Массивы - это простой способ хранить списки без awk и временных файлов. Главное знать базовые приемы.
▪️ Добавление элементов
bash сам раздвигает индексы, дыры допустимы.
▪️ Удаление элементов
Элемент удаляется, но индексы не сдвигаются:
Удалить весь массив:
▪️ Перебор элементов
Правильно:
Неправильно (ломает пробелы):
▪️ Перебор с индексами
▪️ Размер массива
BashTex📱 #bash
Массивы - это простой способ хранить списки без awk и временных файлов. Главное знать базовые приемы.
arr=(one two)
arr+=(three)
arr[5]=six
bash сам раздвигает индексы, дыры допустимы.
unset arr[1]
Элемент удаляется, но индексы не сдвигаются:
echo "${!arr[@]}" # индексы
Удалить весь массив:
unset arr
Правильно:
for item in "${arr[@]}"; do
echo "$item"
done
Неправильно (ломает пробелы):
for item in ${arr[@]}; do
for i in "${!arr[@]}"; do
echo "$i => ${arr[$i]}"
done
echo "${#arr[@]}"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍3
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10
Проверка времени отклика сервисов
Когда сервис работает, но пользователи жалуются на медлительность, нужно мерить не аптайм, а отклик. Это легко сделать обычным curl.
▪️ Самый простой замер
Показывает общее время выполнения запроса и быстро понять, тормозит или нет.
▪️ Точнее: только сетевое время
Полезные метрики:
Пример:
▪️ Проверка нескольких сервисов
▪️ Таймаут обязателен
Без таймаута любой мониторинг бесполезен.
BashTex📱 #bash #utils
Когда сервис работает, но пользователи жалуются на медлительность, нужно мерить не аптайм, а отклик. Это легко сделать обычным curl.
time curl -s https://bashtex.com > /dev/null
Показывает общее время выполнения запроса и быстро понять, тормозит или нет.
curl -s -o /dev/null -w "time_total: %{time_total}\n" https://bashtex.com
Полезные метрики:
time_namelookup
time_connect
time_starttransfer
time_totalПример:
curl -w "DNS:%{time_namelookup} CONNECT:%{time_connect} TTFB:%{time_starttransfer} TOTAL:%{time_total}\n" \
-o /dev/null -s https://bashtex.com
for url in https://a.ru https://b.ru; do
curl -o /dev/null -s -w "$url %{time_total}\n" "$url"
done
curl --connect-timeout 3 --max-time 5 https://bashtex.com
Без таймаута любой мониторинг бесполезен.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Поиск забытых .ssh директорий
После чистки пользователей в системе нередко остаются их .ssh-каталоги. Это мусор + потенциальная дыра: старые ключи могут лежать годами.
▪️ Быстрый поиск по системе
Найдет все .ssh, включая:
нестандартные каталоги
▪️ Проверяем, существует ли владелец
Если владелец:
UNKNOWN
или пользователь отсутствует в
то каталог подозрительный.
▪️ Поиск .ssh без пользователя
⚠️ Перед удалением лучше сделать архив
BashTex📱 #bash #utils
После чистки пользователей в системе нередко остаются их .ssh-каталоги. Это мусор + потенциальная дыра: старые ключи могут лежать годами.
find / -type d -name .ssh 2>/dev/null
Найдет все .ssh, включая:
/home/*/.ssh
/root/.sshнестандартные каталоги
find / -type d -name .ssh -exec stat -c '%U %n' {} \;
Если владелец:
UNKNOWN
или пользователь отсутствует в
/etc/passwdто каталог подозрительный.
while read user path; do
id "$user" &>/dev/null || echo "Лишний: $path"
done < <(find / -type d -name .ssh -exec stat -c '%U %n' {} \;)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Циклы while vs for - где что правильно
В bash оба цикла нужны, но для разных задач. Путаница между ними - источник проблем.
▪️ for - перебор готового списка. Используй, когда список уже есть.
файлы;
аргументы "$@";
элементы массива.
⚠️ Пример ошибок:
▪️ while - поток данных. Идеален для чтения ввода.
строки с пробелами;
вывод команд;
большие файлы.
⚠️ Частая ошибка:
(цикл в subshell!)
BashTex📱 #bash
В bash оба цикла нужны, но для разных задач. Путаница между ними - источник проблем.
for f in *.log; do
echo "$f"
done
файлы;
аргументы "$@";
элементы массива.
for f in $(ls *.log); do # ломается на пробелах
while IFS= read -r line; do
echo "$line"
done < file.txt
строки с пробелами;
вывод команд;
большие файлы.
cat file | while read line; do
count=$((count+1)) # переменная пропадёт
done
(цикл в subshell!)
for не является универсальным, а while безопаснее для данных. Перед созданием цикла нужно задавать себе вопрос: список или поток.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Контроль свободных inode на дисках
Можно иметь 50% свободного места и при этом… не создать ни одного файла. Причина: закончились inode.
▪️ Проверка inode на дисках
▪️ Когда это становится проблемой
миллионы мелких файлов (cache, maildir, tmp)
Docker overlay
Типичная ошибка:
…при пустом диске.
▪️ Поиск пожирателей inode
Или по каталогам:
▪️ Что делать
чистить cache и tmp
пересоздать FS с большим inode ratio (если хронически)
BashTex📱 #bash
Можно иметь 50% свободного места и при этом… не создать ни одного файла. Причина: закончились inode.
df -i
Ключевые колонки:Inodes- всегоIUsed- использованоIFree- свободноIUse%- процент
миллионы мелких файлов (cache, maildir, tmp)
Docker overlay
/var/spool, /tmp, /var/libТипичная ошибка:
No space left on device
…при пустом диске.
find /var -xdev -type f | wc -l
Или по каталогам:
for d in /var/*; do
echo "$(find "$d" -type f | wc -l) $d"
done
чистить cache и tmp
пересоздать FS с большим inode ratio (если хронически)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5😁1🗿1
Контроль роста каталогов во времени
Проблема знакомая: диск внезапно кончается, а кто именно его съел - непонятно. Решение простое: снимать размеры каталогов и сравнивать во времени.
1️⃣ Делаем снимок. Сохраняем размеры верхнеуровневых директорий:
сортировка сразу по размеру
2️⃣ Сравниваем со вчера. Если есть предыдущий снимок:
Или удобнее, показать только рост:
На выходе список каталогов, которые реально выросли, с дельтой.
▪️ Зачем это нужно
быстро найти runaway-логи;
поймать тихий рост кешей;
понять, кто ест диск, а не гадать
BashTex📱 #bash #utils
Проблема знакомая: диск внезапно кончается, а кто именно его съел - непонятно. Решение простое: снимать размеры каталогов и сравнивать во времени.
du -x --max-depth=1 /var 2>/dev/null | sort -n > /tmp/var.size.today
-x - не уходим на другие FS--max-depth=1 - только первый уровеньсортировка сразу по размеру
diff -u /tmp/var.size.yesterday /tmp/var.size.today
Или удобнее, показать только рост:
join -1 2 -2 2 \
<(sort -k2 /tmp/var.size.yesterday) \
<(sort -k2 /tmp/var.size.today) \
| awk '{delta=$3-$1; if (delta>0) printf "%+dK %s\n", delta, $2}' \
| sort -n
На выходе список каталогов, которые реально выросли, с дельтой.
быстро найти runaway-логи;
поймать тихий рост кешей;
понять, кто ест диск, а не гадать
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Работа с временными метками файлов
В linux у каждого файла есть не только размер, но и время. И на этом можно строить полезную автоматику.
▪️ Какие метки бывают
⚠️ ctime - не дата создания
▪️ Получаем время в виде числа. Для сравнений удобнее epoch:
Текущее время:
▪️ Пример: файл старше N минут
▪️ Сравнение двух файлов
Полезно для: автопересборки конфигов или выбора актуального бэкапа
▪️ Практика: очистка старых файлов
BashTex📱 #bash #utils
В linux у каждого файла есть не только размер, но и время. И на этом можно строить полезную автоматику.
stat file.txt
Главные поля:
Modify (mtime) - когда менялось содержимое
Access (atime) - когда читали
Change (ctime) - менялись права / владелец
stat -c %Y file.txt # mtime в секундах
Текущее время:
now=$(date +%s)
mtime=$(stat -c %Y file.log)
(( now - mtime > 600 )) && echo "Файл старше 10 минут"
f1=$(stat -c %Y a.conf)
f2=$(stat -c %Y b.conf)
(( f1 > f2 )) && echo "a.conf новее"
Полезно для: автопересборки конфигов или выбора актуального бэкапа
for f in /tmp/*; do
(( now - $(stat -c %Y "$f") > 86400 )) && rm -f "$f"
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Автоперезапуск сервиса только если он упал больше N раз
Иногда сервис падает один раз - это нормально. Но если он падает 10 раз за минуту, бесконечный Restart=always только усугубляет проблему.
Задача: перезапускать сервис только если он упал больше N раз за период.
1️⃣ Считаем падения через systemd. У systemd есть счетчик рестартов:
Вывод:
2️⃣ Простая логика в bash
▪️ Учитываем период времени
Счетчик накапливается с момента запуска systemd.
Чтобы учитывать последний час, можно смотреть journal:
Или искать Main process exited.
BashTex📱 #bash #utils
Иногда сервис падает один раз - это нормально. Но если он падает 10 раз за минуту, бесконечный Restart=always только усугубляет проблему.
Задача: перезапускать сервис только если он упал больше N раз за период.
systemctl show nginx -p NRestarts
Вывод:
NRestarts=3
SERVICE=nginx
LIMIT=5
restarts=$(systemctl show "$SERVICE" -p NRestarts --value)
if (( restarts >= LIMIT )); then
echo "Сервис падал $restarts раз — перезапуск"
systemctl restart "$SERVICE"
else
echo "Падений мало ($restarts) — не трогаем"
fi
Счетчик накапливается с момента запуска systemd.
Чтобы учитывать последний час, можно смотреть journal:
journalctl -u nginx --since "1 hour ago" | grep -c "Started"
Или искать Main process exited.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8
Маунт есть, а доступа нет
Представим ситуацию, mount показывает, что файловая система подключена, но при заходе в каталог: Permission denied.
1️⃣ Проверяем права на каталог
Важно:
владелец
группа
права (rwx)
Даже если диск смонтирован, права на точку монтирования остаются критичны.
Исправление:
2️⃣ Проверяем UID/GID (часто с NFS). На NFS или при миграции: пользователь есть, но UID отличается
Проверка:
Если UID не совпадает, то и доступ будет запрещен.
Решение:
синхронизировать UID
или использовать anonuid/anongid (для NFS)
3️⃣ Смотрим опции монтирования
Частые виновники:
ro - read-only
noexec
nosuid
nodev
Перемонтировать:
4️⃣ SELinux (тихий убийца доступа). Если права нормальные, но доступ запрещен:
Проверка контекста:
Исправление:
5️⃣ Root_squash (NFS-специфика). На NFS root может стать nobody. Проверка экспорта:
Если включен
6️⃣ ACL могут перекрывать права
ACL могут запретить доступ даже при chmod 777.
BashTex📱 #bash
Представим ситуацию, mount показывает, что файловая система подключена, но при заходе в каталог: Permission denied.
ls -ld /mnt/data
Важно:
владелец
группа
права (rwx)
Даже если диск смонтирован, права на точку монтирования остаются критичны.
Исправление:
chown user:group /mnt/data
chmod 755 /mnt/data
Проверка:
id user
ls -ln /mnt/data
Если UID не совпадает, то и доступ будет запрещен.
Решение:
синхронизировать UID
или использовать anonuid/anongid (для NFS)
mount | grep /mnt/data
Частые виновники:
ro - read-only
noexec
nosuid
nodev
Перемонтировать:
mount -o remount,rw /mnt/data
getenforce
Проверка контекста:
ls -Z /mnt/data
Исправление:
restorecon -Rv /mnt/data
exportfs -v
Если включен
root_squash, root не всесилен.
getfacl /mnt/data
ACL могут запретить доступ даже при chmod 777.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥1
Поиск сервисов без логов
Сервис запущен, порт слушает, CPU есть, а в логах тишина и это может быть опасно т.к: нет аудита, нет диагностики, нельзя понять, что происходит. Будем пробовать искать их.
1️⃣ Проверяем, куда вообще пишет сервис
Смотрим:
Loaded
Active
путь к unit-файлу
Далее:
Если:
StandardOutput=null
StandardError=null
это означает, что логирование отключено.
2️⃣ Проверяем journal
Если пусто, а сервис активен:
3️⃣ Проверяем, есть ли вообще лог-файлы. Иногда сервис пишет в файл, а не в journal:
Или:
4️⃣ Проверяем stdout/stderr процесса
Если дескрипторы 1 и 2 указывают в /dev/null - сервис глухой.
5️⃣ Смотрим конфиг самого приложения. Часто в конфиге:
6️⃣ Мини-детектор тихих сервисов. Проверяем активные сервисы без событий в journal за час:
BashTex📱 #bash #utils
Сервис запущен, порт слушает, CPU есть, а в логах тишина и это может быть опасно т.к: нет аудита, нет диагностики, нельзя понять, что происходит. Будем пробовать искать их.
systemctl status myservice
Смотрим:
Loaded
Active
путь к unit-файлу
Далее:
systemctl show myservice -p StandardOutput -p StandardError
Если:
StandardOutput=null
StandardError=null
это означает, что логирование отключено.
journalctl -u myservice --since "1 hour ago"
Если пусто, а сервис активен:
systemctl is-active myservice
lsof -p $(pgrep -x myservice) | grep log
Или:
ls -l /var/log | grep myservice
ls -l /proc/$(pgrep -x myservice)/fd
Если дескрипторы 1 и 2 указывают в /dev/null - сервис глухой.
log_level = none
logging = false
daemon = true
for s in $(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}'); do
count=$(journalctl -u "$s" --since "1 hour ago" | wc -l)
(( count == 0 )) && echo "Тихий сервис: $s"
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5
Почему сервис не стартует?
1️⃣ Быстрая проверка статуса
2️⃣ Смотрим реальные ошибки из journal
3️⃣ Проверяем unit-файл
Проверка синтаксиса:
4️⃣ Типовые причины, которые встречаются чаще всего
🤩 Неверный путь к бинарнику:
Файл не существует и сервис не стартует.
🤩 Порт уже занят
🤩 Неправильные права
Нужно проверить владельца и execute-бит.
🤩 Ошибка в конфиге приложения. Попробуй запустить вручную:
🛠 Небольшой скрипт диагностики
Запуск:
BashTex📱 #bash #utils
systemctl status myservice -n 20 --no-pager
Смотрим:
Loaded
Active
ExecStart
последние строки логов
journalctl -u myservice -xe --no-pager
Частые сообщения:
Permission denied
No such file or directory
Address already in use
Failed to bind
Unit entered failed state
systemctl cat myservice
Ошибки часто здесь:
неправильный путь в ExecStart
забыли daemon-reload
лишний User=
отсутствующая рабочая директория
Проверка синтаксиса:
systemd-analyze verify /etc/systemd/system/myservice.service
ExecStart=/usr/bin/appФайл не существует и сервис не стартует.
ss -lntp | grep 8080
ls -l /path/to/app
Нужно проверить владельца и execute-бит.
sudo -u serviceuser /usr/bin/app
#!/bin/bash
SERVICE="$1"
echo "=== STATUS ==="
systemctl status "$SERVICE" -n 10 --no-pager
echo
echo "=== LAST ERRORS ==="
journalctl -u "$SERVICE" -n 20 --no-pager
echo
echo "=== UNIT FILE ==="
systemctl cat "$SERVICE"
echo
echo "=== PORT CHECK ==="
ss -lntp | grep "$(systemctl show "$SERVICE" -p ExecStart --value | awk '{print $1}')" 2>/dev/null
Запуск:
./diag.sh nginx
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10