BashTex | Linux – Telegram
BashTex | Linux
2.55K subscribers
47 photos
9 videos
291 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

Подойдет для разработчиков, системных администраторов и DevOps

Реклама: @dad_admin
Download Telegram
Создание своего systemd-сервиса для скрипта

Если у тебя есть полезный скрипт, который должен запускаться как сервис (например, при старте системы или по крону не подходит) - самое время подружить его с systemd.

1️⃣ Подготовка скрипта. Убедись, что скрипт исполняемый и логирует всё в файл:


#!/bin/bash
echo "$(date): Скрипт запущен" >> /var/log/mynoscript.log
# Здесь твоя логика
Сохрани его, например, в /usr/local/bin/mynoscript.sh


И не забудь дать права:


chmod +x /usr/local/bin/mynoscript.sh


2️⃣ Юнит-файл systemd. Создай сервис:


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


3️⃣ Активация и запуск


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 📱 #linux #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥3
Умная работа с PID: поиск и завершение зависших процессов

Иногда процессы зависают - висят в 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 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍2
А, ой, я случайно

BashTex 📱 #юмор
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. 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 📱 #linux #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥3👨‍💻1
Логирование доступа к файлам через auditd

Если ты хочешь знать, кто и когда открыл или изменил важные файлы на сервере - добро пожаловать в мир 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 📱 #linux #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥2
Автоматическая настройка нового пользователя и окружения на сервере

Когда ты создаёшь нового пользователя в 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 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Второго свидания не будет, но теперь она знает лучший дистрибутив

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁27👍1
Проверка целостности бэкапов и перезапись повреждённых архивов

Сделать бэкап - это только половина дела. Вторая - убедиться, что он рабочий. Повреждённый архив может стать критичной точкой отказа, особенно при аварийном восстановлении. Попробуем автоматизировать проверку и реагирование.

🌟 Что проверяем? Если вы делаете архивы в .tar.gz, .zip, .xz и т.п., то можно автоматически:

Проверить, читается ли архив
Отправить уведомление при ошибке
Пересоздать архив, если он битый


📱 Пример скрипта:


#!/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 — ежедневная проверка по расписанию


❗️ Уведомления: Интеграция с TG или Email - чтобы вы знали, что пошло не так:


curl -s -X POST https://api.telegram.org/bot$TOKEN/sendMessage \
-d chat_id=$CHAT_ID -d text="Архив повреждён: $file. Запущен новый бэкап."


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍1
Анализ попыток входа и автоматическая блокировка

Один из способов защиты 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 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥3
Уведомление о подключении внешнего устройства

Хочешь получать уведомления, когда кто-то подключает флешку к серверу или рабочей станции? Это возможно с помощью udev и небольшого скрипта.

Когда в Linux подключается новое устройство, ядро отправляет событие в подсистему udev. Мы можем отследить это событие и выполнить любую команду - например, отправить уведомление в телеграмм или записать в лог.

1️⃣ 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).

2️⃣ Скрипт уведомления. Создай файл:


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


3️⃣ Применение


sudo udevadm control --reload
sudo udevadm trigger


Проверь, подключив USB-накопитель. Устройство должно появиться, и ты получишь сообщение или запись в лог.

🌟 Советы

1. Используй SUBSYSTEM=="usb" и ENV{ID_USB_DRIVER}=="usb-storage" для более узкой фильтрации.
2. Чтобы поймать все события - смотри udevadm monitor.
3. Уведомления можно расширить: звуковое оповещение, email, системное всплывающее сообщение.

Это будет полезно на серверах, где подключение внешних накопителей должно отслеживаться.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥1
Я могу все и даже больше!

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁20
Сравнение вывода команд без временных файлов с помощью process substitution

Когда нужно сравнить результат работы двух команд, большинство сразу сохраняет их в файлы:


команда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)


📍 Сравнение вывода команд systemd


diff <(systemctl list-units --type=service | grep running) <(cat snapshot.txt)


⚡️ Полезно:

1. Работает не только с diff, но и с comm, cmp, vimdiff и др.
2. Используется только в bash и совместимых шеллах (не POSIX-совместимо).
3. <(...) — это подстановка процесса, создающая временный дескриптор.


🔥 Фишка: можно использовать diff -u для наглядного вывода различий:


diff -u <(sort файл_до.log) <(sort файл_после.log)


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
Создаем CLI-подобные скрипты с флагами и аргументами

Когда скрипт обрастает опциями (-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)) после парсинга, чтобы работать с позиционными аргументами.


⭐️ Мини-шаблон CLI:


#!/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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20
Фоновый Bash-демон, отслеживающий сетевые соединения

Иногда нужно знать, кто подключается к вашей системе - особенно если это сервер с внешним доступом. Мы можем написать лёгкий 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


▪️ Настройка автозапуска как systemd-сервиса


# /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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍2🫡2😁1
Автообновление и откат systemd-сервисов с логированием

Когда сервис критичен, обновление "в лоб" - плохая идея. Ошибка в новом бинаре или конфиге может повалить всё. Решение? Безопасное автообновление с возможностью мгновенного отката и логированием. Всё на 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


▪️ Подключение как systemd-timer. Чтобы запускать обновление по расписанию:


# /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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥2
Интеграция Bash и JSON: системная информация как API

Если ты мониторишь серверы или хочешь получать данные с хоста в внешнюю систему (через Prometheus, телеграмм-бота, Grafana или просто cron), удобно возвращать информацию в формате JSON.

Что можно собрать?

- Загрузка CPU и RAM
- Место на диске
- Аптайм
- IP-адрес
- Имя хоста
- Статус сетевого соединения
- Наличие процессов и сервисов


▪️ Пример скрипта с JSON-выводом:


#!/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-запрос:


curl -X POST -H "Content-Type: application/json" \
-d "$(bash system_info.sh)" http://your.monitoring.local/endpoint


BashTex 📱 #bash #monitoring
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Путь к счастью

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17
trap и ERR: превращаем скрипт в «черный ящик» для отладки

Когда скрипт падает - хочется понять где, почему и с каким кодом ошибки. Вместо угадываний можно сделать систему отлова ошибок и логирования через 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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
declare -n: когда переменные становятся ссылками

В Bash 4.3+ появилась фича - nameref, или "ссылочные переменные". Она позволяет работать с переменной по её имени, как с указателем. Удобно для динамического доступа, написания функций и шаблонов.

Что такое declare -n?


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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Централизованный сбор логов аутентификации с rsyslog

Если у вас несколько серверов, то хранить логи аутентификации локально - так себе вариант. Централизованный сбор через rsyslog упрощает аудит. Ниже - как организовать сбор логов auth.log или secure с клиента на лог-сервер.

1️⃣ На стороне клиента (отправителя логов). Открываем конфиг rsyslog:


sudo nano /etc/rsyslog.conf


2️⃣ Раскомментируем или добавляем строку:


*.* @@logserver.example.com:514


@ - UDP, @@ - TCP. Лучше использовать TCP.

3️⃣ Убедитесь, что строки логов аутентификации отправляются:


sudo nano /etc/rsyslog.d/50-default.conf


Проверьте, что auth,authpriv.* не закомментированы.

4️⃣ Перезапускаем rsyslog:


sudo systemctl restart rsyslog


1️⃣ На стороне лог-сервера (получателя логов). Открываем /etc/rsyslog.conf:


sudo nano /etc/rsyslog.conf


2️⃣ Включаем модуль приёма:


module(load="imtcp") # для TCP
input(type="imtcp" port="514")


3️⃣ Добавляем правило записи логов клиентов:


$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 и т.д.

4️⃣ Перезапускаем:


sudo systemctl restart rsyslog


Такой подход позволяет в одном месте отслеживать неудачные попытки входа, sudo-команды, доступ по SSH и прочее.

BashTex 📱 #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ротационные бэкапы с экономией места: rsync + hardlink

На сервере делаются ежедневные резервные копии, но не хочется тратить кучу места на дублирование одних и тех же файлов?
Есть отличный способ - использовать 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 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥1