ru
Feedback
BashTex | Linux

BashTex | Linux

Открыть в Telegram

Авторский канал для тех, кто хочет глубже погрузиться в мир Linux. Подойдет для разработчиков, системных администраторов и DevOps Реклама: @dad_admin

Больше
2 524
Подписчики
Нет данных24 часа
-67 дней
+230 день
Архив постов
Контроль размера логов и архивация быстро растущих файлов Неловко будет если кто-то включил дебаг, забыл про него и оставил так, даже на выходные. Покажу скрипт который будет: мониторить размер файлов в директории логов, сравнивать с предыдущим значением, при подозрительном росте - архивировать лог и обнулять его, сохраняя копию. 🛠 Скрипт

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/myapp"
STATE_FILE="/tmp/log_sizes.db"
THRESHOLD_MB=50   # если лог вырос более чем на 50 MB - архивируем
ARCHIVE_DIR="/var/log/archive"

mkdir -p "$ARCHIVE_DIR"
touch "$STATE_FILE"

# читаем прошлые размеры
declare -A old_sizes
while IFS=":" read -r file size; do
    old_sizes["$file"]="$size"
done < "$STATE_FILE"

> "$STATE_FILE"  # перезапишем свежим состоянием

for log in "$LOG_DIR"/*.log; do
    [[ -f "$log" ]] || continue
    size=$(stat -c %s "$log")
    echo "$log:$size" >> "$STATE_FILE"

    old_size=${old_sizes["$log"]:-0}
    diff=$(( (size - old_size) / 1024 / 1024 ))

    if (( diff > THRESHOLD_MB )); then
        ts=$(date +%F_%H-%M-%S)
        archive="$ARCHIVE_DIR/$(basename "$log").$ts.gz"

        echo "$log вырос на ${diff}MB - архивируем в $archive"
        cp "$log" "$archive"
        gzip "$archive"
        : > "$log"   # обнуляем лог
    fi
done
▪️ Пояснение: хранит состояние предыдущих размеров в log_sizes.db, если файл вырос больше порога, делает копию с timestamp, архивирует и очищает, работает для всех *.log в выбранной директории. ▪️ Применение. Добавь в cron для регулярной проверки:

*/10 * * * * /usr/local/bin/log_watch.sh
BashTex 📱 #bash

👩‍💻 Всем программистам посвящается! Вот 17 авторских обучающих IT каналов по самым востребованным областям программирования
👩‍💻 Всем программистам посвящается! Вот 17 авторских обучающих IT каналов по самым востребованным областям программирования: Выбирай своё направление: 🤔 InfoSec & Хакинг — t.me/hacking_ready 👩‍💻 Python — t.me/python_ready 👩‍💻 Linux — t.me/linux_ready 🖼️ DevOpst.me/devops_ready 👩‍💻 Bash & Shell — t.me/bash_ready 🖥 Data Sciencet.me/data_ready 🖥 SQL & Базы Данных — t.me/sql_ready 🤖 Нейросетиt.me/neuro_ready 👩‍💻 C/C++ — https://t.me/cpp_ready 👩‍💻 C# & Unity — t.me/csharp_ready 📱 GameDevt.me/csharp_ready 👩‍💻 IT Новости — t.me/it_ready 👩‍💻 Java — t.me/java_ready 🐞 QA-тестирование t.me/qa_ready 📖 IT Книги — t.me/books_ready 👩‍💻 Frontend — t.me/frontend_ready 📱 JavaScript — t.me/javascript_ready 👩‍💻 Backend — t.me/backend_ready 📱 GitHub & Git — t.me/github_ready 📁 IT Факты — t.me/it_facts 🖥 Design — t.me/design_ready 📌 Гайды, шпаргалки, задачи, ресурсы и фишки для каждого языка программирования!

Использование printf -v для динамического формирования переменных Бывает, что нужно создавать или заполнять переменные с динамическими именами: item_1, item_2, user_alice и т.д. Вместо eval попробуем использовать встроенный printf -v, который позволяет записать форматированный строковый результат прямо в переменную по имени.
Почему printf -v лучше, чем eval? безопаснее (без спаивания и выполнения произвольного кода), дает форматирование (числа, нули, float), удобно в функциях (можно создавать глобальные переменные через declare -g).
▪️ Базовый пример: простая запись

name="user_alice"
printf -v "$name" "%s" "id=42"
echo "$user_alice"

id=42
Здесь мы записали строку в переменную user_alice без eval. ▪️ Нумерация с форматированием (zero-padding)

for i in {1..5}; do
  printf -v "item_%03d" "$i" "val_$i"
done

# показать созданные переменные
for i in {1..5}; do
  var="item_$(printf '%03d' "$i")"
  echo "$var = ${!var}"
done

item_001 = val_1
item_002 = val_2
printf -v "item_%03d" "$i" "val" - формат имени и значение удобно комбинировать. ▪️ Создаем набор конфигов из CSV (пример)

while IFS=, read -r key value; do
  # нормализовать имя (латиница, цифры, _)
  safe_key=$(echo "$key" | tr -c '[:alnum:]_' '_')
  printf -v "cfg_%s" "$safe_key" "%s" "$value"
done <<'CSV'
db.host,localhost
db.port,5432
feature.enable,true
CSV

echo "Host: $cfg_db_host"
echo "Port: $cfg_db_port"
echo "Feature: $cfg_feature_enable"
▪️ Инспекция созданных переменных

# показать все переменные с префиксом cfg_
for v in ${!cfg_*}; do
  echo "$v = ${!v}"
done
(indirect expansion) позволяет получить значение переменной по имени. ▪️ Комбинация с declare -n (nameref)

printf -v "user_alice" "%s" "alice@bashtex.com"
ref_var="user_alice"
declare -n userref="$ref_var"
echo "Email via nameref: $userref"
declare -n дает ссылку на переменную, это удобнее, чем постоянно подставлять ${!name}. ▪️ Как избежать проблем с именами переменных. Переменная должна соответствовать правилам имени в bash. Можно валидировать:

sanitize() {
  printf '%s' "$1" | sed 's/[^a-zA-Z0-9_]/_/g'
}

raw="user-name@host"
safe=$(sanitize "$raw")
printf -v "$safe" "%s" "value"
Если допустить в имени пробелы или символы ; - printf -v либо даст ошибку, либо поведет себя непредсказуемо. BashTex 📱 #bash #utils

Создание резервных копий БД с шифрованием Правильный подход к шифрованию БД, чтобы не оставлять персональные данные открытыми это: создать дамп → зашифровать его GPG → сохранить/отправить. ▪️ Подготовка GPG. На сервере, который будет создавать бэкапы, импортируйте публичный ключ:

gpg --import backup_public.key
Проверьте наличие ключа:

gpg --list-keys
Использовать будем шифрование public key → private key, так что дешифровать можно только на безопасном ПК/сервере. 🛠 Скрипт универсального бэкапа PostgreSQL/MySQL с шифрованием GPG

#!/usr/bin/env bash
set -euo pipefail

# === Настройки ===
BACKUP_DIR="/var/backups/db"
RETENTION_DAYS=7
GPG_RECIPIENT="backup@bashtex.com"   # email из публичного ключа
TS=$(date +"%F_%H-%M-%S")

DB_TYPE="$1"          # postgres | mysql
DB_NAME="$2"          # имя базы
DB_USER="$3"          # пользователь

mkdir -p "$BACKUP_DIR"

DUMP_FILE="$BACKUP_DIR/${DB_TYPE}_${DB_NAME}_${TS}.sql"
ENC_FILE="$DUMP_FILE.gpg"
LOG_FILE="$BACKUP_DIR/backup.log"

# === Логгер ===
log() {
    echo "[$(date +%F_%T)] $*" | tee -a "$LOG_FILE"
}

log "=== Старт резервного копирования $DB_TYPE:$DB_NAME ==="

# === Дамп базы ===
case "$DB_TYPE" in
    postgres)
        log "Выполняю pg_dump…"
        pg_dump -U "$DB_USER" "$DB_NAME" > "$DUMP_FILE"
        ;;
    mysql)
        log "Выполняю mysqldump…"
        mysqldump -u "$DB_USER" "$DB_NAME" > "$DUMP_FILE"
        ;;
    *)
        log "Неизвестный тип БД: $DB_TYPE"
        exit 1
        ;;
esac

log "Дамп создан: $DUMP_FILE"

# === Шифрование GPG ===
log "Шифрую дамп для получателя: $GPG_RECIPIENT"
gpg --yes --encrypt --recipient "$GPG_RECIPIENT" "$DUMP_FILE"

log "Шифрованный файл: $ENC_FILE"

# === Удаление оригинального дампа ===
rm -f "$DUMP_FILE"
log "Оригинальный файл удалён"

# === Очистка старых бэкапов ===
log "Удаление файлов старше $RETENTION_DAYS дней"
find "$BACKUP_DIR" -type f -name "*.gpg" -mtime "+$RETENTION_DAYS" -delete

log "Готово"
Скрипт: делает бэкап PostgreSQL или MySQL; шифрует его GPG-ключом; сохраняет с датой; удаляет старые копии. логирует все происходящее
▪️ Запуск PostgreSQL:

./backup.sh postgres mydb dbuser
MySQL/MariaDB:

./backup.sh mysql mydb root
▪️ Как восстановить?

gpg -d backup_postgres_mydb_2025-11-01_03-00-00.sql.gpg > restore.sql
PostgreSQL:

psql -U postgres mydb < restore.sql
MySQL:

mysql -u root mydb < restore.sql
BashTex 📱 #bash #utils

⚡️ Запускаем крупный розыгрыш призов, где можно выиграть iPhone 17, игровые наушники, клавиатуру и мышь! Без лишних слов, усл
⚡️ Запускаем крупный розыгрыш призов, где можно выиграть iPhone 17, игровые наушники, клавиатуру и мышь! Без лишних слов, условия: 1. Подписка на: — бизнестрендсТехнотрендыБлумберг 2. Нажать кнопку «Участвовать» снизу Итоги будут опубликованы 15 ноября в 18:00 на наших каналах, желаем удачи!

Автообновление python-зависимостей в виртуальных окружениях В проектах на python у меня неоднократно возникала ситуация: виртуальное окружение развернуто давно, а пакеты внутри уже устарели. Чтобы не держать руками список и не забывать про обновления, можно автоматизировать этот процесс. 1️⃣ Получение списка пакетов. В активированном окружении pip list --outdated --format=freeze вернет пакеты, которые можно обновить:

source venv/bin/activate
pip list --outdated --format=freeze
2️⃣ Скрипт автообновления. Скрипт ищет все устаревшие пакеты и обновляет их до последней версии:

#!/bin/bash
set -euo pipefail

VENV_PATH="./venv"
source "$VENV_PATH/bin/activate"

echo "Проверяем устаревшие пакеты..."
outdated=$(pip list --outdated --format=freeze | cut -d= -f1)

if [[ -z "$outdated" ]]; then
    echo "Все пакеты актуальны"
    exit 0
fi

echo "Обновляем пакеты:"
for pkg in $outdated; do
    echo " - $pkg"
    pip install -U "$pkg"
done
3️⃣ Массовое обновление для проектов. Если проектов несколько, можно пройтись по каталогам и обновить все:

#!/bin/bash
for dir in ~/projects/*; do
    if [[ -d "$dir/venv" ]]; then
        echo "=== $dir ==="
        source "$dir/venv/bin/activate"
        pip list --outdated --format=freeze | cut -d= -f1 | xargs -n1 pip install -U
        deactivate
    fi
done
4️⃣ Фиксируем версии. Перед обновлением полезно сохранить текущие версии, чтобы в случае проблем легко откатиться:

pip freeze > requirements-$(date +%F).txt
BashTex 📱 #bash #utils

Мониторинг логов с реакцией Если вы не хотите заморачиваться с созданием триггера, а нужно просто отловить ошибку один раз и забыть про нее, то есть вариант сделать это только с помощью bash. 1️⃣ Реакция на ошибку в логах

tail -f /var/log/syslog | grep --line-buffered "error" | while read line; do
    notify-send "Ошибка в логах!" "$line"
done
Каждая новая строка с error вызывает уведомление на рабочем столе. 2️⃣ Отправка алертов на почту

tail -f /var/log/nginx/error.log | grep --line-buffered "timeout" | while read line; do
    echo "$line" | mail -s "Alert Alert! Help!!!" admin@bashtex.com
done
По событию будет отправлено письмо на почту. 3️⃣ Подсчет в реальном времени

tail -f /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c
Видно, какие IP чаще всего обращаются к серверу. BashTex 📱 #bash

Компактный контроль фоновых процессов При работе с фоновыми процессами в скриптах часто возникает два вопроса: 1. Как реагировать на завершение первого из них, не дожидаясь всех? 2. Как корректно снять всю пачку, если что-то пошло не так? В Bash на этот случай имеется удобный механизм: wait -n и управление группами процессов. ▪️ Проблема: несколько фоновых задач. Допустим, мы запускаем несколько параллельных процессов:

#!/bin/bash
long_task_1 &
long_task_2 &
long_task_3 &
Обычно wait ждет завершения всех процессов. Но что если нужно отреагировать на первый фейл или отменить остальных после успешной задачи? Решение: wait -n. Команда wait -n ждет завершения любого из фоновых процессов и возвращает его код выхода. Как пример: запускаем 3 задачи, как только одна успешно завершилась - гасим остальные:

#!/bin/bash
cmd1 & p1=$!
cmd2 & p2=$!
cmd3 & p3=$!

while true; do
    if wait -n; then
        echo "Одна из задач завершилась успешно, убиваем остальные..."
        kill $p1 $p2 $p3 2>/dev/null
        break
    fi
done
▪️ Kill group: гасим всю пачку. У kill есть прием: если передать отрицательный PID, сигнал уйдет всей группе процессов.

# запустить группу
( cmd1 & cmd2 & cmd3 & wait ) &

# сохранить PID группы
PGID=$!

# ... позже убить всех одним движением:
kill -- -$PGID
Это удобно, если внутри группы запускаются дочерние процессы, которые обычный kill $PID не заденет. ▪️ Комбо. Представим сценарий: несколько загрузчиков качают один и тот же файл из разных зеркал. Как только первый скачал успешно - убиваем остальных.

#!/bin/bash
(
  curl -s -O http://mirror1/file.iso &
  curl -s -O http://mirror2/file.iso &
  curl -s -O http://mirror3/file.iso &
  wait -n   # ждем первый завершившийся процесс
  kill -- -$$   # убиваем всю группу (все ещё живые curl)
) &
wait
echo "Файл получен!"
BashTex 📱 #bash #utils

Нужна оптимизация BashTex 📱 #юмор
Нужна оптимизация BashTex 📱 #юмор

Как выполнить команду без следов Многие знают, что bash сохраняет введенные команды в ~/.bash_history. Но иногда, когда требуется ввести пароль в команде или использовать одноразовый токен, хочется, чтобы этого не было в истории. 📌 Решение: начни команду с пробела. Если в .bashrc (или глобально в /etc/bash.bashrc) включена опция:

HISTCONTROL=ignoreboth
то любая команда, набранная с пробелом в начале, не попадет в историю. ▪️ Пример:

# обычная команда - сохраняется в истории
echo "hello"

# команда с пробелом - не будет в history
 echo "secret run"
▪️ Полезные комбинации с HISTCONTROL ignoredups - не сохранять дубликаты подряд. ignorespace - не сохранять команды, начинающиеся с пробела. Можно управлять этим через .bashrc:

export HISTCONTROL=ignoreboth
export HISTSIZE=5000
export HISTFILESIZE=10000
BashTex 📱 #bash

Терпите. BashTex 📱 #юмор
Терпите. BashTex 📱 #юмор

Канал про Kubernetes без ванильной теории. Только хардкор из бигтеха, опыт, набитый на реальных продах, щепотка IT-юмора и, к
Канал про Kubernetes без ванильной теории. Только хардкор из бигтеха, опыт, набитый на реальных продах, щепотка IT-юмора и, конечно, мой кот Маркус — у него чуйка на баги. Я — Виталий Лихачев, SRE в крупном голландском тревелтехе.  У себя на канале делюсь:  🫸 Мясом по Kubernetes: как оно на самом деле работает (и фейлится) в больших конторах. 🫸 Боевыми лайфхаками и граблями, собранными в энтерпрайзных траншеях. 🫸 Регулярными вебинарами и прямыми эфирами — живое общение, ответы на каверзные вопросы. Если K8s для тебя – это не просто набор букв, а ежедневная задача (и боль, разумеется), то welcome, обсудим конфиги и не только. ➡️Канал «Kubernetes и кот Лихачева»

Cтатистика по сетевым соединениям 1️⃣ Быстрая сводка: сколько вообще соединений. Используем ss - он современнее netstat и есть почти везде.

ss -s
Пример вывода:

Total: 1024 (kernel 2048)
TCP:   512 (estab 200, closed 10, orphaned 0, synrecv 0, timewait 55/0), ports 0
UDP:   256
RAW:   0
2️⃣ Топ IP по количеству соединений (TCP). Самый распространенный прием - взять список активных соединений и посчитать, какие удаленные IP встречаются чаще всего.

ss -tn state established '( dport != :22 )' \
  | awk '{print $5}' \
  | sed 's/:[0-9]*$//' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -n 20
ss -tn state established - TCP, только установленные соединения; $5 в выводе ss - удалённый адрес (remote:port); sed убирает порт; uniq -c | sort -nr - считаем и сортируем по убыванию. Пример вывода:

120  203.0.113.42
87   198.51.100.10
45   10.0.0.5
...
3️⃣ Топ удаленных портов (куда подключаются клиенты). Иногда важно понять, на какие порты чаще всего идут входящие соединения:

ss -tn state established \
  | awk '{print $4}' \
  | sed 's/.*://; s/::ffff://g' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -n 20
Здесь мы берем локальный адрес $4 и вычленяем порт. Пример вывода:

340  443
200  80
50   22
...
4️⃣ Показать top IP + процесс (PID). Хочется не только IP, но и процесс, который держит соединения:

ss -tnp | awk '/ESTAB/ { split($6, a, ":"); ip=a[1]; match($0, /pid=[0-9]+,/, m); pid=(m[0]=="")? "?" : substr(m[0],5,length(m[0])-5); print ip, pid }' \
  | sort | uniq -c | sort -nr | head -n 30
ss -tnp выводит PID/program в конце строки, мы парсим это и группируем. Пример вывода:

50  203.0.113.42  2345
30  198.51.100.10 5012
...
Интерпретация: 203.0.113.42 имеет 50 соединений, принадлежащих процессу с PID 2345. 5️⃣ Однострочник: показать какие процессы создают больше всего соединений. Если нужно быстро понять, какие программы держат трафик:

ss -tnp | awk '/ESTAB/ { if (match($0, /pid=([0-9]+),/ , m)) { pid=m[1]; sub(/^.*pid=[0-9]+, /,""); proc=$0; split(proc,p," "); print pid, p[1] } }' \
  | sort | uniq -c | sort -nr | head -n 20
Результат - счетчик + PID + имя процесса. 6️⃣ Оценка трафика (байты) - через iptables счётчики. ss не всегда дает удобную сумму байт на IP. Для оценки трафика по IP удобно использовать iptables счетчики (если вы можете изменять правила). Создадим правило для счёта байт/пакетов входящего/исходящего трафика:

# создать chain для мониторинга (однократно)
sudo iptables -N MONITOR 2>/dev/null || true
sudo iptables -I INPUT -j MONITOR
sudo iptables -I OUTPUT -j MONITOR

# добавить правило для конкретного IP (пример)
sudo iptables -I MONITOR -s 203.0.113.42 -j ACCEPT

# посмотреть счётчики
sudo iptables -L MONITOR -vn --line-numbers
Вывод покажет количество пакетов/байтов для каждого правила - можно парсить и сохранять в CSV. 7️⃣ Несколько полезных примеров про запас Топ слушающих сокетов (портов на сервере):

ss -lnpt | awk '{print $4}' | sed 's/.*://; /^[[:space:]]*$/d' | sort | uniq -c | sort -nr
Топ активных UDP-адресов:

ss -un | awk '{print $5}' | sed 's/:[0-9]*$//' | sort | uniq -c | sort -nr | head
Полный список соединений с PID и программой:

ss -tnp | sed 's/  */ /g' | awk '{print $1, $4, $5, $6}'
BashTex 📱 #bash

PROMPT_COMMAND Недавно на форуме arch linux увидел такую штуку:

export PROMPT_COMMAND='[[ $curdir != $PWD ]] && ls -a; curdir=$PWD'
при каждом входе в новую директорию автоматически вызывается ls -a. А все дело в переменной окружения PROMPT_COMMAND - bash выполняет ее перед выводом нового приглашения. Если разобраться, можно превратить её в инструмент автоматизации. ▪️ Базовые сценарии 📍 Автолистинг при смене директории

PROMPT_COMMAND='[[ $lastdir != $PWD ]] && ls; lastdir=$PWD'
ls срабатывает только если реально поменяли директорию. 📍 Показ текущей git-ветки

PROMPT_COMMAND='branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null); PS1="[\u@\h \W${branch:+ ($branch)}]\\$ "'
приглашение (PS1) динамически обновляется: добавляет (ветка) только в репозитории. 📍Отображение количества фоновых задач

PROMPT_COMMAND='jobs_count=$(jobs -p | wc -l); PS1="[jobs:$jobs_count] \u@\h:\w\$ "'
рядом с промптом видим, сколько задач выполняется в фоне. ▪️ Продвинутые хаки 📍 Время последней команды

PROMPT_COMMAND='PS1="[\t] \u@\h:\w\$ "'
каждый раз в начале промпта вставляется текущее время. 📍 Звуковой сигнал при ошибке

PROMPT_COMMAND='[ $? -ne 0 ] && echo -ne "\a"'
если последняя команда завершилась ошибкой (exit code != 0), терминал пищит. 📍История + логирование всех команд

PROMPT_COMMAND='history -a; history -c; history -r'
история сохраняется сразу (не только при выходе из shell), что полезно при одновременных сессиях. ▪️ Комбо вариант

PROMPT_COMMAND='
  [[ $lastdir != $PWD ]] && ls; lastdir=$PWD;
  branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null);
  jobs_count=$(jobs -p | wc -l);
  PS1="[jobs:$jobs_count ${branch:+git:$branch}] \u@\h:\w\$ "
'
- при смене директории автоматом делается ls - в промпте видно количество фоновых задач - в git-репозитории показывается текущая ветка BashTex 📱 #bash #utils

🔧 Для системных администраторов и IT-специалистов! Ищете надежный источник знаний и поддержки? Тогда вам к нам! 📚 Что у нас
🔧 Для системных администраторов и IT-специалистов! Ищете надежный источник знаний и поддержки? Тогда вам к нам! 📚 Что у нас есть: - Книги по Cisco Systems, Mikrotik, VoIP, Linux и Windows Server - Руководства по сетевым технологиям - 📽 Видеоуроки на актуальные темы - 🤝 Поддержка от сообщества Присоединяйтесь к нашему сообществу профессионалов: @sysadmin1

😊 BashTex 📱 #юмор
😊 BashTex 📱 #юмор

Копирование между хостами без SCP Сегодня поделюсь с вами альтернативным способом копирования между хостами, когда SCP недоступен или файлы лежат в приватной сети. ▪️ Отправка каталога по SSH На источнике:

tar cz dir_to_copy \
  | base64 \
  | ssh user@remote "base64 -d | tar xz"
dir_to_copy упаковывается в tar.gz, кодируется base64, передается по SSH и на удаленном хосте раскодируется и распаковывается. ▪️ Копирование через буфер (без SCP и SSH) На источнике:

tar cz myfile.txt | base64
Копируем вывод в буфер и затем на приемнике:

base64 -d | tar xz
Вставляем скопированное содержимое и файл восстановится Работает даже там, где SCP недоступен. ▪️ Обмен папками между хостами без сети Через tmux buffer или screen можно передавать данные вообще без файлов и SSH, просто через терминал. Пример в tmux: На сервере А:

tar cz project | base64 | tmux load-buffer -
На сервере Б:

tmux save-buffer - | base64 -d | tar xz
🌟 Для больших архивов можно добавить pv и тогда будет видно прогресс:

tar cz bigdir | pv | base64 | ssh host "base64 -d | tar xz"
BashTex 📱 #bash #utils

ЧЕБУРНЕТУ БЫТЬ!🤭 Медный купол по-немногу накрывает, а ты даже не знаешь как действовать? Ниже даю список каналов спецов из с
ЧЕБУРНЕТУ БЫТЬ!🤭
Медный купол по-немногу накрывает, а ты даже не знаешь как действовать?
Ниже даю список каналов спецов из сферы кибербеза, которые уже придумали все за тебя: HACK WARRIOR. – парни уже давно сели на измену и активно постируют контент на тему защиты своих личных данных в интернете, чтобы не сел ты. secure sector – канал безопасника однажды сильно пострадавшего от халатного отношения к своей интернет-гигиене. Собственно, поэтому и стал безопасником... INFOSEC LIZARD – твой личный криптонит от любых кибер-угроз в сети. Я бы не хотел, чтобы в будущем ты пожалел о том, что пролистал этот пост. Оставайся в безопасности.

Сравнение конфигов на разных серверах через md5sum ▪️ Сравнение директорий по контрольным суммам

# На сервере A:
find /etc -type f -print0 \
  | sort -z \
  | xargs -0 md5sum > /tmp/etc-hash.txt

# На сервере B:
find /etc -type f -print0 \
  | sort -z \
  | xargs -0 md5sum > /tmp/etc-hash.txt
Затем можно скопировать файлы на локальный хост и сравнить:

diff -u serverA/etc-hash.txt serverB/etc-hash.txt
Отличия будут видны построчно: какие файлы отличаются и какие отсутствуют. ▪️ Более гибкий вариант Хэшируем сразу несколько директорий и добавляем префикс хоста:

for h in server1 server2; do
  ssh $h 'find /etc -type f -print0 \
            | sort -z \
            | xargs -0 md5sum' \
    | sed "s|^|$h |"
done > all-hashes.txt
Теперь легко фильтровать:

awk '{print $2,$1}' all-hashes.txt | sort | uniq -c
Если файл совпадает на всех хостах - будет одинаковая хэш-сумма. Если разный - сразу видно у какого сервера отличается. BashTex 📱 #bash #utils

Bash как оркестратор Многие используют docker-compose или kubectl apply напрямую, но часто в реальной инфраструктуре требуются условные проверки, ветвления, откаты, повторные попытки. И тут bash оказывается неожиданно полезным инструментом. ▪️ Пример 1. Bash + docker-compose

#!/usr/bin/env bash
set -euo pipefail

echo "[*] Deploying database..."
docker-compose -f compose.db.yml up -d
sleep 10

echo "[*] Checking DB health..."
docker-compose exec db pg_isready -U postgres || {
    echo "DB is not ready, aborting!"
    exit 1
}

echo "[*] Deploying app..."
docker-compose -f compose.app.yml up -d
Скрипт запускает сначала базу, ждет, проверяет ее готовность и только потом запускает приложение. Такой контроль docker-compose сам по себе не умеет. ▪️ Пример 2. Bash + Kubernetes

#!/usr/bin/env bash
set -euo pipefail

NAMESPACE="staging"

echo "[*] Applying secrets..."
kubectl apply -f secrets.yml -n $NAMESPACE

echo "[*] Deploying app..."
kubectl apply -f app.yml -n $NAMESPACE

echo "[*] Waiting for rollout..."
kubectl rollout status deployment/myapp -n $NAMESPACE --timeout=60s || {
    echo "Rollout failed, rolling back..."
    kubectl rollout undo deployment/myapp -n $NAMESPACE
}
Тут добавлена проверка статуса роллаута и откат, если приложение не поднялось. ▪️ Пример 3. Управление конфигами и миграциями Bash может быть связующим звеном: сначала подгружаем env-настройки, потом запускаем миграции БД, и только если они успешны - применяем манифесты.

source .env

echo "[*] Running migrations..."
docker-compose run --rm app ./manage.py migrate || exit 1

echo "[*] Applying manifests..."
kubectl apply -f k8s/ -n $NAMESPACE
BashTex 📱 #bash