Создание своего systemd-сервиса для скрипта
Если у тебя есть полезный скрипт, который должен запускаться как сервис (например, при старте системы или по крону не подходит) - самое время подружить его с systemd.
1️⃣ Подготовка скрипта. Убедись, что скрипт исполняемый и логирует всё в файл:
И не забудь дать права:
2️⃣ Юнит-файл systemd. Создай сервис:
Пример содержимого:
3️⃣ Активация и запуск
Проверка:
🌟 Зачем это вообще?
🌟 Советы:
BashTex📱 #linux #utils
Если у тебя есть полезный скрипт, который должен запускаться как сервис (например, при старте системы или по крону не подходит) - самое время подружить его с systemd.
#!/bin/bash
echo "$(date): Скрипт запущен" >> /var/log/mynoscript.log
# Здесь твоя логика
Сохрани его, например, в /usr/local/bin/mynoscript.sh
И не забудь дать права:
chmod +x /usr/local/bin/mynoscript.sh
sudo nano /etc/systemd/system/mynoscript.service
Пример содержимого:
[Unit]
Denoscription=Мой кастомный скрипт
After=network.target
[Service]
ExecStart=/usr/local/bin/mynoscript.sh
Restart=on-failure
User=root
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable mynoscript.service
sudo systemctl start mynoscript.service
Проверка:
systemctl status mynoscript.service
Скрипт запускается при старте
Контролируется systemd (перезапуск, статус, логи)
Удобная интеграция в системную инфраструктуру
Нужен таймер? Используйmynoscript.timer
Хочешь лог в journalctl? - уже встроено
Скрипт должен зависеть от другого сервиса? Укажи в After= и Requires=
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥3
Умная работа с PID: поиск и завершение зависших процессов
Иногда процессы зависают - висят в D (disk sleep) или Z (zombie), потребляют CPU без пользы, или держат файлы, которые нужно удалить. Просто killall - грубо и может снести лишнее. Давайте сделаем это умнее.
▪️ Задача:
Найти и безопасно завершить только зависшие или чрезмерно "прожорливые" процессы, избегая случайных убийств важных задач.
▪️ Подход:
▪️ Пример скрипта:
▪️ Что умеет:
BashTex📱 #bash
Иногда процессы зависают - висят в D (disk sleep) или Z (zombie), потребляют CPU без пользы, или держат файлы, которые нужно удалить. Просто killall - грубо и может снести лишнее. Давайте сделаем это умнее.
Найти и безопасно завершить только зависшие или чрезмерно "прожорливые" процессы, избегая случайных убийств важных задач.
Сканируем ps на предмет "подозрительных" состояний.
Проверяем длительность жизни процесса.
Ограничиваем по имени, CPU или статусу.
Включаем dry-run перед действием.
#!/usr/bin/env bash
set -euo pipefail
PATTERN="python" # Имя процесса (или часть имени)
MAX_CPU=80 # Максимально допустимая загрузка CPU
MAX_AGE=3600 # В секундах: 1 час
DRY_RUN=true # Безопасный режим
echo "Поиск процессов по шаблону: $PATTERN"
ps -eo pid,etime,pcpu,comm --sort=-pcpu | awk -v pattern="$PATTERN" -v max_cpu="$MAX_CPU" -v max_age="$MAX_AGE" -v dry_run="$DRY_RUN" '
function hms_to_sec(s, t, n, h, m) {
gsub("-", "", s)
n = split(s, t, /[:-]/)
if (n == 3) { h = t[1]; m = t[2]; s = t[3] }
else if (n == 2) { h = 0; m = t[1]; s = t[2] }
else { h = 0; m = 0; s = t[1] }
return h * 3600 + m * 60 + s
}
NR>1 && $4 ~ pattern {
age = hms_to_sec($2)
cpu = $3
if (cpu > max_cpu || age > max_age) {
printf "[!] Найден подозрительный процесс: PID=%s CPU=%.1f%% AGE=%ss CMD=%s\n", $1, cpu, age, $4
if (dry_run == "false") {
system("kill -9 " $1)
print "[x] Завершен PID=" $1
} else {
print "[i] Dry run: процесс НЕ завершен"
}
}
}
Выборочно завершает процессы с перегрузкой по CPU
Проверяет "возраст" процессов по etime
Работает в dry-run режиме по умолчанию
Прост в кастомизации: ищи по имени, статусу, времени
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
☃20🫡2👨💻1
Сравнение производительности: grep / awk / sed / perl
Когда дело доходит до обработки текста в Linux, у нас есть классическая "великая четвёрка": grep, awk, sed, perl. Все они умеют искать и преобразовывать строки, но что выбрать, если важна производительность?
⭐️ Тест: кто быстрее?
Возьмём файл на 1 млн строк (logs.txt) и задачу - найти строки, содержащие "ERROR" и вывести их.
🕛 Результаты (примерные):
🌟 Что важно помнить:
🌟 Хитрости: Для поиска без регулярных выражений:
1.
2. Используй
3. Объединяй:
BashTex📱 #linux #utils
Когда дело доходит до обработки текста в Linux, у нас есть классическая "великая четвёрка": grep, awk, sed, perl. Все они умеют искать и преобразовывать строки, но что выбрать, если важна производительность?
Возьмём файл на 1 млн строк (logs.txt) и задачу - найти строки, содержащие "ERROR" и вывести их.
# 1. grep — специализируется на поиске
time grep 'ERROR' logs.txt
# 2. awk — универсален, но чуть медленнее grep
time awk '/ERROR/' logs.txt
# 3. sed — может искать, но не для этого заточен
time sed -n '/ERROR/p' logs.txt
# 4. perl - мощь и регулярки, но запускается дольше
time perl -ne 'print if /ERROR/' logs.txt
Команда Время (сек) Комментарий
grep 0.18 - Самый быстрый в чистом поиске
awk 0.25 - Универсал, чуть медленнее
sed 0.30 - Не лучший для просто поиска
perl 0.35 - 0.50 Мощно, но медленно стартует
grep - лучший выбор для быстрого поиска. Используй grep -F (fixed strings) для ещё большей скорости.
awk - когда нужна логика: фильтрация, подсчёты, агрегирование.
sed - идеально для простых замен (особенно sed -i), но не лучший инструмент для поиска.
perl - тянет даже сложнейшие регулярки и постобработку, но стоит дороже по времени запуска.
1.
grep -F "ERROR" → быстрее, чем обычный grep.2. Используй
LC_ALL=C или LANG=C для ускорения поиска (отключает локализацию):
LC_ALL=C grep 'ERROR' logs.txt
3. Объединяй:
grep 'ERROR' logs.txt | awk '{print $1}' # вытащить дату, например
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥3👨💻1
Логирование доступа к файлам через auditd
Если ты хочешь знать, кто и когда открыл или изменил важные файлы на сервере - добро пожаловать в мир
⚙️ Установка:
▪️ Отслеживаем доступ к файлу. Допустим, тебе важно следить за файлом
▪️ Пример события в логе:
📱 Скрипт для анализа:
▪️ Как убрать правило:
▪️ Расширение идеи:
Нужно логировать доступ к нескольким файлам? Добавь их в список и прогоняй в цикле.
BashTex📱 #linux #utils
Если ты хочешь знать, кто и когда открыл или изменил важные файлы на сервере - добро пожаловать в мир
auditd. Это подсистема аудита Linux, а вместе с Bash она превращается в инструмент контроля безопасности.auditd - демон ядра, который пишет события доступа к ресурсам (файлам, системным вызовам, пользователям и т.д.) в лог /var/log/audit/audit.log.
sudo apt install auditd audispd-plugins # Debian/Ubuntu
sudo yum install audit -y # RHEL/CentOS
/etc/shadow:
sudo auditctl -w /etc/shadow -p rwxa -k shadow_watch
-w — путь к файлу
-p — права (read/write/execute/attribute)
-k — метка (ключ) для фильтрации логов
type=SYSCALL msg=audit(1613403003.244:516): ...
type=PATH msg=audit(1613403003.244:516): item=0 name="/etc/shadow" ...
#!/bin/bash
KEY="shadow_watch"
LOG="/var/log/audit/audit.log"
REPORT="/var/log/shadow_access_report.txt"
echo "Анализ доступа к /etc/shadow — $(date)" > "$REPORT"
ausearch -k "$KEY" | \
grep 'name="/etc/shadow"' | \
awk -F"uid=" '{print $2}' | \
awk '{print $1}' | \
sort | uniq -c | sort -nr >> "$REPORT"
cat "$REPORT"
ausearch позволяет фильтровать события по ключу. Скрипт покажет сколько раз какой UID обращался к файлу.
sudo auditctl -W /etc/shadow
Нужно логировать доступ к нескольким файлам? Добавь их в список и прогоняй в цикле.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥2
Автоматическая настройка нового пользователя и окружения на сервере
Когда ты создаёшь нового пользователя в Linux, особенно для dev/stage-серверов, каждый раз настраивать окружение вручную - трата времени. Попробуем автоматизировать процесс: скрипт добавит пользователя, настроит SSH, переменные окружения, alias'ы и даже zsh или tmux - по вкусу.
🌟 Что делает скрипт:
📱 Пример скрипта:
▪️ Расширения:
▪️ Хранение шаблонов
Для advanced-сценариев: можно использовать шаблоны с /etc/skel/ или Ansible playbooks для развёртывания целого окружения под одного пользователя.
BashTex📱 #bash
Когда ты создаёшь нового пользователя в Linux, особенно для dev/stage-серверов, каждый раз настраивать окружение вручную - трата времени. Попробуем автоматизировать процесс: скрипт добавит пользователя, настроит SSH, переменные окружения, alias'ы и даже zsh или tmux - по вкусу.
Создаёт пользователя с паролем
Добавляет в группу sudo
Копирует SSH-ключ для входа
Устанавливает alias'ы и переменные окружения
Устанавливает и настраивает Zsh/Tmux (опционально)
#!/bin/bash
USERNAME="$1"
PUBKEY_PATH="$2" # путь до публичного ключа, например ~/.ssh/id_rsa.pub
if [[ -z "$USERNAME" || -z "$PUBKEY_PATH" ]]; then
echo "Использование: $0 <имя_пользователя> <путь_до_публичного_ключа>"
exit 1
fi
# Создание пользователя
useradd -m -s /bin/bash "$USERNAME"
usermod -aG sudo "$USERNAME"
echo "$USERNAME:changeme" | chpasswd # можно заменить на генерацию пароля
# Настройка SSH
mkdir -p /home/$USERNAME/.ssh
cp "$PUBKEY_PATH" /home/$USERNAME/.ssh/authorized_keys
chmod 700 /home/$USERNAME/.ssh
chmod 600 /home/$USERNAME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME /home/$USERNAME/.ssh
# Bash-окружение
cat >> /home/$USERNAME/.bashrc <<EOF
# Custom environment
alias ll='ls -lah'
export EDITOR=nano
EOF
# Установка zsh (опционально)
if command -v zsh &>/dev/null; then
chsh -s $(which zsh) "$USERNAME"
fi
echo "Пользователь $USERNAME создан и настроен."
1. Добавить установку oh-my-zsh или tmux конфигов
2. Автоматически генерировать пароль и сохранять его в файл
3. Настраивать .vimrc, .gitconfig или Docker-окружение
4. Добавить пост-инсталляционный скрипт: установка утилит, обновления и пр.
Для advanced-сценариев: можно использовать шаблоны с /etc/skel/ или Ansible playbooks для развёртывания целого окружения под одного пользователя.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Please open Telegram to view this post
VIEW IN TELEGRAM
😁27👍1
Проверка целостности бэкапов и перезапись повреждённых архивов
Сделать бэкап - это только половина дела. Вторая - убедиться, что он рабочий. Повреждённый архив может стать критичной точкой отказа, особенно при аварийном восстановлении. Попробуем автоматизировать проверку и реагирование.
🌟 Что проверяем? Если вы делаете архивы в .tar.gz, .zip, .xz и т.п., то можно автоматически:
📱 Пример скрипта:
⭐️ Дополнительно:
❗️ Уведомления: Интеграция с TG или Email - чтобы вы знали, что пошло не так:
BashTex📱 #bash
Сделать бэкап - это только половина дела. Вторая - убедиться, что он рабочий. Повреждённый архив может стать критичной точкой отказа, особенно при аварийном восстановлении. Попробуем автоматизировать проверку и реагирование.
Проверить, читается ли архив
Отправить уведомление при ошибке
Пересоздать архив, если он битый
#!/bin/bash
BACKUP_DIR="/mnt/backups"
LOGFILE="/var/log/backup-check.log"
RETRY_SCRIPT="/usr/local/bin/backup.sh" # ваш основной бэкап-скрипт
check_tar() {
tar -tzf "$1" > /dev/null 2>&1
}
for file in "$BACKUP_DIR"/*.tar.gz; do
if [[ -f "$file" ]]; then
echo -n "Проверка $file... " >> "$LOGFILE"
if check_tar "$file"; then
echo "OK" >> "$LOGFILE"
else
echo "FAILED" >> "$LOGFILE"
echo "[$(date)] Архив повреждён: $file. Перезапуск бэкапа..." >> "$LOGFILE"
# Удалить битый архив
rm -f "$file"
# Перезапуск создания бэкапа
bash "$RETRY_SCRIPT" >> "$LOGFILE" 2>&1
fi
fi
done
1. Для .zip: unzip -t архив.zip
2. Для .xz: xz -t архив.xz
3. Можно хранить хэши (sha256sum) при создании и сверять перед восстановлением
4. Интеграция с cron — ежедневная проверка по расписанию
curl -s -X POST https://api.telegram.org/bot$TOKEN/sendMessage \
-d chat_id=$CHAT_ID -d text="Архив повреждён: $file. Запущен новый бэкап."
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍1
Анализ попыток входа и автоматическая блокировка
Один из способов защиты Linux-системы - мониторинг неудачных попыток входа. Сегодня покажу пример скрипта, который:
📱 Скрипт:
⭐️ Как использовать:
1. Замените your_token и your_chat_id на свои данные TG-бота.
2. Убедитесь, что скрипт имеет root-доступ (для iptables и passwd).
3. Добавьте в crontab:
Такой подход ближе к самописному fail2ban, но с расширенной логикой.
BashTex📱 #bash
Один из способов защиты Linux-системы - мониторинг неудачных попыток входа. Сегодня покажу пример скрипта, который:
📍 анализирует лог /var/log/auth.log,📍 определяет IP и пользователей, совершивших >10 неудачных попыток входа за 10 минут,📍 автоматически блокирует IP через iptables на 3 часа,📍 блокирует пользователя через passwd -l на 1 час,📍 отправляет уведомление в телеграмм,📍 и по таймеру снимает блокировку.
#!/bin/bash
LOG="/var/log/auth.log"
TMP="/tmp/login_check.tmp"
MAX_ATTEMPTS=10
TIME_WINDOW=600 # 10 минут
TELEGRAM_TOKEN="your_token"
CHAT_ID="your_chat_id"
IP_BLOCK_LIST="/tmp/ip_blocked.list"
USER_BLOCK_LIST="/tmp/user_blocked.list"
touch "$IP_BLOCK_LIST" "$USER_BLOCK_LIST"
NOW=$(date +%s)
# Удаляем истёкшие блокировки
grep -vE "^[^ ]+ [^ ]+ [0-9]+$" "$IP_BLOCK_LIST" > "$IP_BLOCK_LIST.tmp" && mv "$IP_BLOCK_LIST.tmp" "$IP_BLOCK_LIST"
grep -vE "^[^ ]+ [0-9]+$" "$USER_BLOCK_LIST" > "$USER_BLOCK_LIST.tmp" && mv "$USER_BLOCK_LIST.tmp" "$USER_BLOCK_LIST"
# Чтение лога и подсчёт попыток
grep "Failed password" "$LOG" | \
awk -v now="$NOW" -v limit="$TIME_WINDOW" '
{
match($0, /([A-Z][a-z]{2} [0-9]{1,2} [0-9:]{8})/, m);
cmd = "date -d\"" m[1] "\" +%s";
cmd | getline t;
close(cmd);
if (now - t <= limit) {
for (i=1;i<=NF;i++) {
if ($i == "from") ip=$(i+1);
if ($i == "for" && $(i+1) != "invalid") user=$(i+1);
}
if (ip != "" && user != "") print ip, user;
}
}' | sort | uniq -c | sort -nr > "$TMP"
# Обработка IP и пользователей
while read count ip user; do
if (( count >= MAX_ATTEMPTS )); then
# Блокировка IP
if ! grep -q "$ip " "$IP_BLOCK_LIST"; then
iptables -I INPUT -s "$ip" -j DROP
expire=$((NOW + 10800)) # 3 часа
echo "$ip $user $expire" >> "$IP_BLOCK_LIST"
curl -s -X POST https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage \
-d chat_id="$CHAT_ID" -d text="IP $ip заблокирован на 3 часа за $count неудачных попыток входа." > /dev/null
fi
# Блокировка пользователя
if ! grep -q "^$user " "$USER_BLOCK_LIST"; then
passwd -l "$user" 2>/dev/null
expire_user=$((NOW + 3600)) # 1 час
echo "$user $expire_user" >> "$USER_BLOCK_LIST"
curl -s -X POST https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage \
-d chat_id="$CHAT_ID" -d text="Учетка $user заблокирована на 1 час." > /dev/null
fi
fi
done < "$TMP"
# Снятие IP-блоков
while read ip user expire; do
if (( NOW >= expire )); then
iptables -D INPUT -s "$ip" -j DROP
sed -i "\|^$ip $user|d" "$IP_BLOCK_LIST"
fi
done < "$IP_BLOCK_LIST"
# Снятие блоков с пользователей
while read user expire; do
if (( NOW >= expire )); then
passwd -u "$user" 2>/dev/null
sed -i "\|^$user |d" "$USER_BLOCK_LIST"
fi
done < "$USER_BLOCK_LIST"
1. Замените your_token и your_chat_id на свои данные TG-бота.
2. Убедитесь, что скрипт имеет root-доступ (для iptables и passwd).
3. Добавьте в crontab:
*/5 * * * * /path/to/noscript.sh
Такой подход ближе к самописному fail2ban, но с расширенной логикой.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥3
Уведомление о подключении внешнего устройства
Хочешь получать уведомления, когда кто-то подключает флешку к серверу или рабочей станции? Это возможно с помощью udev и небольшого скрипта.
Когда в Linux подключается новое устройство, ядро отправляет событие в подсистему udev. Мы можем отследить это событие и выполнить любую команду - например, отправить уведомление в телеграмм или записать в лог.
1️⃣ udev-правило. Создаём правило:
Пример:
Это правило сработает при подключении новых разделов (например, /dev/sdb1).
2️⃣ Скрипт уведомления. Создай файл:
Не забудь:
3️⃣ Применение
Проверь, подключив USB-накопитель. Устройство должно появиться, и ты получишь сообщение или запись в лог.
🌟 Советы
1. Используй
2. Чтобы поймать все события - смотри udevadm monitor.
3. Уведомления можно расширить: звуковое оповещение, email, системное всплывающее сообщение.
Это будет полезно на серверах, где подключение внешних накопителей должно отслеживаться.
BashTex📱 #bash #utils
Хочешь получать уведомления, когда кто-то подключает флешку к серверу или рабочей станции? Это возможно с помощью udev и небольшого скрипта.
Когда в Linux подключается новое устройство, ядро отправляет событие в подсистему udev. Мы можем отследить это событие и выполнить любую команду - например, отправить уведомление в телеграмм или записать в лог.
sudo nano /etc/udev/rules.d/99-usb-notify.rules
Пример:
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z][0-9]", RUN+="/usr/local/bin/usb-notify.sh"
Это правило сработает при подключении новых разделов (например, /dev/sdb1).
sudo nano /usr/local/bin/usb-notify.sh
#!/bin/bash
DEVICE="$DEVNAME"
TIME=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$TIME] Подключено устройство: $DEVICE" >> /var/log/usb-connect.log
# Telegram (опционально)
TOKEN="your_bot_token"
CHAT_ID="your_chat_id"
TEXT="USB подключено: $DEVICE в $TIME"
curl -s -X POST https://api.telegram.org/bot$TOKEN/sendMessage \
-d chat_id="$CHAT_ID" -d text="$TEXT" > /dev/null
Не забудь:
chmod +x /usr/local/bin/usb-notify.sh
sudo udevadm control --reload
sudo udevadm trigger
Проверь, подключив USB-накопитель. Устройство должно появиться, и ты получишь сообщение или запись в лог.
1. Используй
SUBSYSTEM=="usb" и ENV{ID_USB_DRIVER}=="usb-storage" для более узкой фильтрации.2. Чтобы поймать все события - смотри udevadm monitor.
3. Уведомления можно расширить: звуковое оповещение, email, системное всплывающее сообщение.
Это будет полезно на серверах, где подключение внешних накопителей должно отслеживаться.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁20
Сравнение вывода команд без временных файлов с помощью process substitution
Когда нужно сравнить результат работы двух команд, большинство сразу сохраняет их в файлы:
Но Bash позволяет сделать это без лишнего мусора на диске, используя подстановку процессов - конструкцию <(команда).
▪️ Пример: сравнение списков установленных пакетов на двух серверах
Bash создаёт два временных именованных канала (FIFO) и подставляет их как файлы. diff "думает", что сравнивает обычные файлы, а на деле - это результат команд.
▪️ Примеры практического применения
📍 Сравнение конфигурации
📍 Проверка различий в ответах веб-приложения (до и после деплоя)
📍 Сравнение вывода команд systemd
⚡️ Полезно:
🔥 Фишка: можно использовать diff -u для наглядного вывода различий:
BashTex📱 #bash #utils
Когда нужно сравнить результат работы двух команд, большинство сразу сохраняет их в файлы:
команда1 > out1.txt
команда2 > out2.txt
diff out1.txt out2.txt
Но Bash позволяет сделать это без лишнего мусора на диске, используя подстановку процессов - конструкцию <(команда).
diff <(ssh server1 'dpkg -l | sort') <(ssh server2 'dpkg -l | sort')
Bash создаёт два временных именованных канала (FIFO) и подставляет их как файлы. diff "думает", что сравнивает обычные файлы, а на деле - это результат команд.
diff <(curl -s http://server1/config.json) <(curl -s http://server2/config.json)
diff <(curl -s https://myapp.com/v1/data) <(curl -s https://myapp.com/v2/data)
diff <(systemctl list-units --type=service | grep running) <(cat snapshot.txt)
1. Работает не только с diff, но и с comm, cmp, vimdiff и др.
2. Используется только в bash и совместимых шеллах (не POSIX-совместимо).
3. <(...) — это подстановка процесса, создающая временный дескриптор.
diff -u <(sort файл_до.log) <(sort файл_после.log)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
Создаем CLI-подобные скрипты с флагами и аргументами
Когда скрипт обрастает опциями (-f, -o, -v и т.д.), его удобно превратить в "настоящую CLI-утилиту". Для этого существует встроенный инструмент -
📱 Пример: скрипт с флагами
🌟 Как это работает?
Внутри case ты обрабатываешь каждый флаг.
Остаток ($@) можно анализировать после shift $((OPTIND - 1)).
🧑💻 Пример запуска:
🌟 Советы:
⭐️ Мини-шаблон CLI:
BashTex📱 #bash #utils
Когда скрипт обрастает опциями (-f, -o, -v и т.д.), его удобно превратить в "настоящую CLI-утилиту". Для этого существует встроенный инструмент -
getopts.getopts - это встроенная функция bash для парсинга коротких флагов (-a, -b value) по POSIX-стандарту.
#!/bin/bash
usage() {
echo "Usage: $0 [-f файл] [-v]"
exit 1
}
verbose=0
file=""
while getopts ":f:v" opt; do
case $opt in
f) file="$OPTARG" ;;
v) verbose=1 ;;
\?) echo "Invalid option: -$OPTARG" >&2; usage ;;
🙂 echo "Option -$OPTARG requires an argument." >&2; usage ;;
esac
done
getopts ":f:v":
: в начале - включает ручную обработку ошибок.
f: - опция -f ожидает аргумент ($OPTARG).
v - флаг без аргумента.
Внутри case ты обрабатываешь каждый флаг.
Остаток ($@) можно анализировать после shift $((OPTIND - 1)).
./mynoscript.sh -f /tmp/data.txt -v
1. getopts не поддерживает длинные флаги (--file), только короткие (-f). Для более сложных CLI можно использовать getopt (внешняя утилита) или перейти на Python/Go.
2. Не забывай делать usage и проверки на обязательные параметры.
3. Удобно использовать шаблон shift $((OPTIND - 1)) после парсинга, чтобы работать с позиционными аргументами.
#!/bin/bash
while getopts ":u:p:h" opt; do
case $opt in
u) user=$OPTARG ;;
p) pass=$OPTARG ;;
h) echo "Usage: $0 -u user -p pass"; exit 0 ;;
*) echo "Invalid option"; exit 1 ;;
esac
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20
Фоновый Bash-демон, отслеживающий сетевые соединения
Иногда нужно знать, кто подключается к вашей системе - особенно если это сервер с внешним доступом. Мы можем написать лёгкий Bash-демон, который будет отслеживать входящие соединения в реальном времени, логировать и даже уведомлять при подозрительной активности.
Скрипт будет запускаться в фоне, опрашивать ss или netstat, фильтровать новые IP-адреса, логировать соединения и уведомлять о каждом новом.
📱 Пример скрипта-демона
▪️ Настройка автозапуска как systemd-сервиса
Такой простой демон может стать способом аудита и обнаружения попыток взлома в реальном времени, особенно на серверах без продвинутого мониторинга.
BashTex📱 #bash #utils
Иногда нужно знать, кто подключается к вашей системе - особенно если это сервер с внешним доступом. Мы можем написать лёгкий Bash-демон, который будет отслеживать входящие соединения в реальном времени, логировать и даже уведомлять при подозрительной активности.
Скрипт будет запускаться в фоне, опрашивать ss или netstat, фильтровать новые IP-адреса, логировать соединения и уведомлять о каждом новом.
#!/bin/bash
LOG="/var/log/connwatch.log"
KNOWN="/tmp/known_ips.txt"
INTERVAL=10
touch "$KNOWN"
log() {
echo "[$(date '+%F %T')] $1" >> "$LOG"
}
while true; do
# Получаем список активных IP-адресов (входящие TCP)
ss -tn src :22 | awk 'NR>1 {print $5}' | cut -d: -f1 | sort -u > /tmp/current_ips.txt
# Находим новые IP-адреса
comm -13 "$KNOWN" /tmp/current_ips.txt > /tmp/new_ips.txt
while read -r ip; do
[[ -n "$ip" ]] || continue
log "Новое подключение: $ip"
# Telegram уведомление (опционально)
TOKEN="your_token"
CHAT_ID="your_chat_id"
MSG="Новое SSH-соединение: $ip"
curl -s -X POST https://api.telegram.org/bot$TOKEN/sendMessage \
-d chat_id="$CHAT_ID" -d text="$MSG" > /dev/null
done < /tmp/new_ips.txt
mv /tmp/current_ips.txt "$KNOWN"
sleep "$INTERVAL"
done
# /etc/systemd/system/connwatch.service
[Unit]
Denoscription=Connection Watcher
[Service]
ExecStart=/usr/local/bin/connwatch.sh
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable --now connwatch.service
Такой простой демон может стать способом аудита и обнаружения попыток взлома в реальном времени, особенно на серверах без продвинутого мониторинга.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍2🫡2😁1
Автообновление и откат systemd-сервисов с логированием
Когда сервис критичен, обновление "в лоб" - плохая идея. Ошибка в новом бинаре или конфиге может повалить всё. Решение? Безопасное автообновление с возможностью мгновенного отката и логированием. Всё на Bash + systemd.
🌟 Как это работает?
📱 Пример скрипта:
▪️ Подключение как systemd-timer. Чтобы запускать обновление по расписанию:
🌟 Что можно улучшить:
BashTex📱 #bash #utils
Когда сервис критичен, обновление "в лоб" - плохая идея. Ошибка в новом бинаре или конфиге может повалить всё. Решение? Безопасное автообновление с возможностью мгновенного отката и логированием. Всё на Bash + systemd.
1. Скрипт обновляет бинарь или конфиг.
2. Перезапускает systemd-сервис.
3. Проверяет статус через systemctl и/или пользовательские тесты.
4. В случае сбоя - откатывает всё.
5. Логирует действия для аудита.
#!/bin/bash
SERVICE="myapp.service"
BIN_DIR="/opt/myapp"
NEW_BIN="/tmp/myapp-new"
BACKUP="$BIN_DIR/myapp.bak"
MAIN_BIN="$BIN_DIR/myapp"
LOG="/var/log/myapp_updater.log"
log() {
echo "[$(date +'%F %T')] $1" >> "$LOG"
}
# Резервная копия текущего бинарника
cp "$MAIN_BIN" "$BACKUP" && log "Создана резервная копия."
# Копируем новый бинарь
cp "$NEW_BIN" "$MAIN_BIN" && chmod +x "$MAIN_BIN" && log "Установлен новый бинарь."
# Перезапускаем сервис
systemctl restart "$SERVICE"
sleep 5
# Проверка статуса
if ! systemctl is-active --quiet "$SERVICE"; then
log "Ошибка! Сервис не запустился. Выполняется откат."
cp "$BACKUP" "$MAIN_BIN"
systemctl restart "$SERVICE"
if systemctl is-active --quiet "$SERVICE"; then
log "Откат успешен."
else
log "Откат не удался. Требуется ручное вмешательство!"
fi
else
log "Сервис успешно обновлён и запущен."
rm -f "$BACKUP"
fi
# /etc/systemd/system/myapp-updater.timer
[Unit]
Denoscription=Update myapp binary daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/myapp-updater.service
[Unit]
Denoscription=Update myapp safely
[Service]
ExecStart=/usr/local/bin/myapp_updater.sh
sudo systemctl daemon-reload
sudo systemctl enable --now myapp-updater.timer
1. Добавить интеграцию с Git или rsync для получения обновлений.
2. Хэш-сравнение файлов (md5sum) перед установкой.
3. Юнит-тест на бинарь/конфиг после замены.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥2
Интеграция Bash и JSON: системная информация как API
Если ты мониторишь серверы или хочешь получать данные с хоста в внешнюю систему (через Prometheus, телеграмм-бота, Grafana или просто cron), удобно возвращать информацию в формате JSON.
❓ Что можно собрать?
▪️ Пример скрипта с JSON-выводом:
▪️ Пример вывода:
❓ Что дальше?
⭐️ Упрощённый curl-запрос:
BashTex📱 #bash #monitoring
Если ты мониторишь серверы или хочешь получать данные с хоста в внешнюю систему (через Prometheus, телеграмм-бота, Grafana или просто cron), удобно возвращать информацию в формате JSON.
- Загрузка CPU и RAM
- Место на диске
- Аптайм
- IP-адрес
- Имя хоста
- Статус сетевого соединения
- Наличие процессов и сервисов
#!/bin/bash
cpu_load=$(awk '{print $1}' /proc/loadavg)
mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
mem_free=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
disk_root=$(df -h / | awk 'NR==2 {print $5}')
uptime=$(uptime -p | sed 's/up //')
ip_addr=$(hostname -I | awk '{print $1}')
hostname=$(hostname)
cat <<EOF
{
"hostname": "$hostname",
"ip": "$ip_addr",
"cpu_load": "$cpu_load",
"memory_total_kb": "$mem_total",
"memory_available_kb": "$mem_free",
"disk_root_usage": "$disk_root",
"uptime": "$uptime"
}
EOF
{
"hostname": "server01",
"ip": "192.168.1.10",
"cpu_load": "0.42",
"memory_total_kb": "8192000",
"memory_available_kb": "6123400",
"disk_root_usage": "45%",
"uptime": "2 days, 4 hours"
}
- Отправляй этот JSON в API внешнего сервиса.
- Подключи к Zabbix, Netdata, Grafana Agent или тг-боту.
- Храни историю в базе (InfluxDB, SQLite, etc.)
curl -X POST -H "Content-Type: application/json" \
-d "$(bash system_info.sh)" http://your.monitoring.local/endpoint
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17
trap и ERR: превращаем скрипт в «черный ящик» для отладки
Когда скрипт падает - хочется понять где, почему и с каким кодом ошибки. Вместо угадываний можно сделать систему отлова ошибок и логирования через trap и ERR. Это способ автоматически выполнять команду при любой ошибке во время выполнения скрипта. Аналогично try/catch, только в стиле Bash.
▪️ Пример: лог ошибок в файл
Теперь при любой ошибке будет лог:
🌟 Что ещё можно логировать?
▪️ Например:
▪️ Сценарий с полным "черным ящиком"
BashTex📱 #bash #utils
Когда скрипт падает - хочется понять где, почему и с каким кодом ошибки. Вместо угадываний можно сделать систему отлова ошибок и логирования через trap и ERR. Это способ автоматически выполнять команду при любой ошибке во время выполнения скрипта. Аналогично try/catch, только в стиле Bash.
#!/bin/bash
set -Eeu -o pipefail
LOGFILE="/tmp/noscript_errors.log"
# Функция, вызываемая при ошибке
error_handler() {
echo "[$(date)] Ошибка в строке $1. Код: $2" >> "$LOGFILE"
}
trap 'error_handler $LINENO $?' ERR
Теперь при любой ошибке будет лог:
[2025-04-29 12:45:03] Ошибка в строке 15. Код: 1
- PID скрипта: $$
- Имя текущей функции: ${FUNCNAME[0]}
- Последнюю выполненную команду: BASH_COMMAND
- Пользователя: $USER
- Текущий каталог: pwd
trap 'echo "[$(date)] Ошибка в $BASH_COMMAND (PID $$, строка $LINENO, пользователь $USER)" >> $LOGFILE' ERR
#!/bin/bash
set -Eeuo pipefail
trap 'echo "[ERROR] [$LINENO] $BASH_COMMAND (exit $?)" >> /var/log/mynoscript_crash.log' ERR
trap 'echo "[INFO] Завершение скрипта: $?" >> /var/log/mynoscript.log' EXIT
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
declare -n: когда переменные становятся ссылками
В Bash 4.3+ появилась фича -
❓ Что такое declare -n?
Теперь ссылка становится псевдонимом для имя_переменной.
▪️ Простой пример
Переменная ref на самом деле редактирует name. Прямая манипуляция через ссылку.
▪️ Реальный кейс: функция, меняющая любую переменную
Без declare -n пришлось бы возвращать значение через stdout или временный файл.
▪️ Пример с массивами
Теперь можно передавать имя массива как аргумент, а не содержимое.
🌟 Важно
BashTex📱 #bash #utils
В Bash 4.3+ появилась фича -
nameref, или "ссылочные переменные". Она позволяет работать с переменной по её имени, как с указателем. Удобно для динамического доступа, написания функций и шаблонов.
declare -n ссылка=имя_переменной
Теперь ссылка становится псевдонимом для имя_переменной.
name="Linux"
declare -n ref=name
echo "$ref" # → Linux
ref="Bash"
echo "$name" # → Bash
Переменная ref на самом деле редактирует name. Прямая манипуляция через ссылку.
update_var() {
declare -n target=$1
target="Новое значение"
}
val="Старое"
update_var val
echo "$val" # → Новое значение
Без declare -n пришлось бы возвращать значение через stdout или временный файл.
arr1=(a b c)
arr2=(1 2 3)
print_array() {
declare -n ref=$1
for item in "${ref[@]}"; do echo "$item"; done
}
print_array arr1
print_array arr2
Теперь можно передавать имя массива как аргумент, а не содержимое.
- Работает только в Bash 4.3+
- declare -n не копирует значение, а создаёт указатель
- Можно делать цепочки: declare -n a=b, declare -n b=c, но лучше не злоупотреблять
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Централизованный сбор логов аутентификации с rsyslog
Если у вас несколько серверов, то хранить логи аутентификации локально - так себе вариант. Централизованный сбор через
1️⃣ На стороне клиента (отправителя логов). Открываем конфиг rsyslog:
2️⃣ Раскомментируем или добавляем строку:
@ - UDP, @@ - TCP. Лучше использовать TCP.
3️⃣ Убедитесь, что строки логов аутентификации отправляются:
Проверьте, что auth,authpriv.* не закомментированы.
4️⃣ Перезапускаем rsyslog:
1️⃣ На стороне лог-сервера (получателя логов). Открываем /etc/rsyslog.conf:
2️⃣ Включаем модуль приёма:
3️⃣ Добавляем правило записи логов клиентов:
Это создаст директорию /var/log/remote/host1/auth.log, /host2/auth.log и т.д.
4️⃣ Перезапускаем:
Такой подход позволяет в одном месте отслеживать неудачные попытки входа, sudo-команды, доступ по SSH и прочее.
BashTex📱 #security
Если у вас несколько серверов, то хранить логи аутентификации локально - так себе вариант. Централизованный сбор через
rsyslog упрощает аудит. Ниже - как организовать сбор логов auth.log или secure с клиента на лог-сервер.
sudo nano /etc/rsyslog.conf
*.* @@logserver.example.com:514
@ - UDP, @@ - TCP. Лучше использовать TCP.
sudo nano /etc/rsyslog.d/50-default.conf
Проверьте, что auth,authpriv.* не закомментированы.
sudo systemctl restart rsyslog
sudo nano /etc/rsyslog.conf
module(load="imtcp") # для TCP
input(type="imtcp" port="514")
$template RemoteAuth,"/var/log/remote/%HOSTNAME%/auth.log"
if ($syslogfacility-text == 'auth' or $syslogfacility-text == 'authpriv') then ?RemoteAuth
& stop
Это создаст директорию /var/log/remote/host1/auth.log, /host2/auth.log и т.д.
sudo systemctl restart rsyslog
Такой подход позволяет в одном месте отслеживать неудачные попытки входа, sudo-команды, доступ по SSH и прочее.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ротационные бэкапы с экономией места: rsync + hardlink
На сервере делаются ежедневные резервные копии, но не хочется тратить кучу места на дублирование одних и тех же файлов?
Есть отличный способ - использовать
🌟 Суть подхода
Бэкапы выглядят как отдельные директории (backup-2025-06-02, backup-2025-06-01), но все неизмененные файлы - это просто ссылки на одни и те же иноды.
Если файл не изменился - он физически не дублируется, а просто переиспользуется в новом бэкапе.
▪️ Структура и логика
Пример каталогов:
daily.0 - свежий бэкап.
daily.1, daily.2, ... - предыдущие снепшоты.
При каждом новом запуске:
старые бэкапы смещаются на +1 (daily.2 → daily.3)
daily.0 создаётся как --link-dest от daily.1
▪️ Скрипт ротационного бэкапа
⭐️ Преимущества
BashTex📱 #bash #utils
На сервере делаются ежедневные резервные копии, но не хочется тратить кучу места на дублирование одних и тех же файлов?
Есть отличный способ - использовать
rsync с жёсткими ссылками (hardlinks) для дедупликации. Это позволяет хранить полные снепшоты, при этом экономя место.Бэкапы выглядят как отдельные директории (backup-2025-06-02, backup-2025-06-01), но все неизмененные файлы - это просто ссылки на одни и те же иноды.
Если файл не изменился - он физически не дублируется, а просто переиспользуется в новом бэкапе.
Пример каталогов:
/backups/
├── daily.0 ← сегодня
├── daily.1 ← вчера
├── daily.2
└── daily.3
daily.0 - свежий бэкап.
daily.1, daily.2, ... - предыдущие снепшоты.
При каждом новом запуске:
старые бэкапы смещаются на +1 (daily.2 → daily.3)
daily.0 создаётся как --link-dest от daily.1
#!/bin/bash
SRC="/home/user"
DEST="/backups"
MAX=7 # сколько дней хранить
# Сдвигаем старые бэкапы
for ((i=MAX-1; i>=0; i--)); do
if [ -d "$DEST/daily.$i" ]; then
mv "$DEST/daily.$i" "$DEST/daily.$((i+1))"
fi
done
# Создаём новый бэкап с дедупликацией
LINK=""
if [ -d "$DEST/daily.1" ]; then
LINK="--link-dest=$DEST/daily.1"
fi
rsync -aAX --delete $LINK "$SRC/" "$DEST/daily.0"
- Каждый бэкап - полный, можно восстановить всё в конкретном состоянии.
- Экономия места - используется только дополнительное место для новых/изменённых файлов.
- Простота восстановления: rsync обратно или просто cp.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥1