Сравнение вывода команд без временных файлов с помощью 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
Контроль целостности /usr/bin — базовая защита от подмены
Один из простых, но эффективных способов обнаружить компрометацию системы - сравнение контрольных сумм бинарей с эталонным списком. Если кто-то подменил ls, sudo или ssh, мы это заметим.
1️⃣ Создание whitelist-файла. Собираем хеши всех бинарников в
Лучше делать это на только что установленной и проверенной системе.
2️⃣ Скрипт для проверки целостности
Не забудьте сделать его исполняемым:
3️⃣ Настройка периодической проверки. Добавьте cron-задание:
И вставить:
Проверка будет происходить каждый день в 03:00, лог - в
⭐️ Что ещё можно сделать:
BashTex📱 #security
Один из простых, но эффективных способов обнаружить компрометацию системы - сравнение контрольных сумм бинарей с эталонным списком. Если кто-то подменил ls, sudo или ssh, мы это заметим.
/usr/bin:
find /usr/bin -type f -executable -exec sha256sum {} \; > /root/usrbin.sha256
Лучше делать это на только что установленной и проверенной системе.
#!/bin/bash
WHITELIST="/root/usrbin.sha256"
LOG="/var/log/usrbin_integrity_check.log"
TMP=$(mktemp)
echo "[INFO] Проверка целостности /usr/bin — $(date)" >> "$LOG"
find /usr/bin -type f -executable -exec sha256sum {} \; > "$TMP"
DIFF=$(diff -u "$WHITELIST" "$TMP")
if [[ -n "$DIFF" ]]; then
echo "[ALERT] Обнаружены изменения!" >> "$LOG"
echo "$DIFF" >> "$LOG"
else
echo "[OK] Изменений не найдено." >> "$LOG"
fi
rm "$TMP"
Не забудьте сделать его исполняемым:
chmod +x /usr/local/bin/check_usrbin.sh
sudo crontab -e
И вставить:
0 3 * * * /usr/local/bin/check_usrbin.sh
Проверка будет происходить каждый день в 03:00, лог - в
/var/log/usrbin_integrity_check.log.- Добавить /usr/sbin, /bin, /sbin — аналогично.
- Сравнивать не только hash, но и размер, время изменения (через stat).
- Использовать aide или tripwire для более продвинутого контроля.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14
Анализ активности пользователей через .bash_history
Если ты хочешь узнать, кто чем занимался на сервере, не прибегая к сложным средствам аудита - начни с простого: разбор
❓ Что можно узнать:
🛠 Пример скрипта:
▪️ Проверка root-пользователя:
А если у вас включён HISTTIMEFORMAT, можно дополнительно привязать команды к датам.
🌟 Этот простой анализ позволяет выявить:
BashTex📱 #security
Если ты хочешь узнать, кто чем занимался на сервере, не прибегая к сложным средствам аудита - начни с простого: разбор
~/.bash_history. Это быстрый способ получить отчёт об активности пользователей, особенно если логи команд не централизуются.📍 Самые часто используемые команды📍 Подозрительные или потенциально опасные действия📍 Время последней активности (если HISTTIMEFORMAT включён)📍 Кто запускал sudo, rm, curl, scp и прочие «чувствительные» команды
#!/bin/bash
REPORT="/tmp/history_report.txt"
KEY_CMDS="sudo|rm|curl|scp|wget|nc|nmap|python|ssh|dd"
echo "Отчёт об активности пользователей - $(date)" > "$REPORT"
echo >> "$REPORT"
for user_home in /home/*; do
user=$(basename "$user_home")
hist_file="$user_home/.bash_history"
[[ -f "$hist_file" ]] || continue
echo "Пользователь: $user" >> "$REPORT"
echo "— Топ 5 команд:" >> "$REPORT"
grep -v '^#' "$hist_file" | awk '{print $1}' | sort | uniq -c | sort -rn | head -n 5 >> "$REPORT"
echo "— Подозрительные команды:" >> "$REPORT"
grep -E "$KEY_CMDS" "$hist_file" | tail -n 5 >> "$REPORT"
echo >> "$REPORT"
done
cat "$REPORT"
grep -E "$KEY_CMDS" /root/.bash_history | tail -n 5
А если у вас включён HISTTIMEFORMAT, можно дополнительно привязать команды к датам.
- кто часто использует sudo, rm -rf, dd
- несанкционированную установку пакетов (apt install, curl | bash)
- запуск сетевых туннелей (ssh -R, ngrok, socat)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Управление процессами после разрыва сессии
Бывало такое: запустил долгую задачу, закрыл терминал - и всё пропало. А что если процесс всё ещё жив, и ты можешь снова им управлять?
Сегодня разберём два инструмента:
🌟 Сценарий: восстановление "осиротевшего" процесса
1️⃣ Запустили задачу без screen или tmux:
2️⃣ Вышли из терминала, но процесс живёт (можно найти через ps или top).
3️⃣ Подключаемся обратно, узнаём PID:
4️⃣ Забираем процесс себе:
Теперь процесс снова управляем - можно читать вывод, отменить Ctrl+C, передать сигналы.
⚙️ Установка
🔥 ts - лог с таймштампами. Хочешь узнать, когда именно что-то произошло в логе?
Пример вывода:
Идеально для cron-скриптов, CI-логов и мониторинга.
❗️ Ограничения и советы
📍 reptyr не всегда работает, если у процесса есть PTY или взаимодействие с stdin.
📍 Чтобы reptyr работал на Ubuntu 20+ - нужно отключить Yama security:
(для постоянства: добавь в
BashTex📱 #bash #utils
Бывало такое: запустил долгую задачу, закрыл терминал - и всё пропало. А что если процесс всё ещё жив, и ты можешь снова им управлять?
Сегодня разберём два инструмента:
ts - из moreutils для запуска с timestampreptyr - для перехвата уже запущенного процесса и перевода его обратно в терминал
some-heavy-task.sh &
ps aux | grep some-heavy-task
reptyr <PID>
Теперь процесс снова управляем - можно читать вывод, отменить Ctrl+C, передать сигналы.
sudo apt install reptyr moreutils # Ubuntu/Debian
sudo yum install reptyr moreutils # RHEL/CentOS
long-running-command | ts '[%Y-%m-%d %H:%M:%S]'
Пример вывода:
[2025-06-10 10:03:10] Запущено обновление системы
[2025-06-10 10:03:25] Завершено без ошибок
Идеально для cron-скриптов, CI-логов и мониторинга.
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
(для постоянства: добавь в
/etc/sysctl.d/10-ptrace.conf)BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8🔥5
Автогенерация help/usage в Bash
Одна из лучших практик при написании bash-утилит - добавлять
🛠 Пример структуры скрипта:
⭐️ Как это работает?
Теперь ты всегда видишь usage в начале файла - и это единственный источник правды.
BashTex📱 #bash #utils
Одна из лучших практик при написании bash-утилит - добавлять
--help, чтобы объяснять, как работает скрипт. Но зачем дублировать описание в заголовке и в коде, если можно использовать один и тот же блок? С помощью cat <<EOF и sed можно генерировать справку прямо из комментариев скрипта.
#!/bin/bash
: <<'USAGE'
my-noscript.sh - полезный инструмент
Использование:
./my-noscript.sh [опции]
Опции:
-h показать помощь
-f FILE указать файл
-v включить подробный вывод
Пример:
./my-noscript.sh -f config.ini -v
USAGE
# Генерация help из заголовка
show_help() {
sed -n "/^: <<'USAGE'/,/^USAGE/p" "$0" | sed '1d;$d'
}
while getopts ":hf:v" opt; do
case $opt in
h) show_help; exit 0 ;;
f) FILE=$OPTARG ;;
v) VERBOSE=1 ;;
\?) echo "Неверный флаг: -$OPTARG" >&2; show_help; exit 1 ;;
esac
done
📍 : <<'USAGE' ... USAGE - это многострочный комментарий.📍 sed -n '/^: <<'\''USAGE'\''/,/^USAGE/p' "$0" - извлекает его.📍 В show_help() мы красиво выводим только нужный блок.
Теперь ты всегда видишь usage в начале файла - и это единственный источник правды.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁19
Управление каталогами через стек путей
Все еще используешь cd туда-сюда, чтобы прыгать по директориям? Попробуй
🌟 Как это работает
▪️ Пример использования
Стек хранит историю твоих переходов, как назад в браузере.
▪️ dirs: просмотр пути
Это означает:
dirs +0 → текущий путь
dirs +1 → предыдущий
popd +1 → убрать второй элемент
❓ Где полезно:
⭐️ Совет: Добавить алиасы для удобства:
BashTex📱 #bash #utils
Все еще используешь cd туда-сюда, чтобы прыгать по директориям? Попробуй
pushd и popd - это как cd, но умнее: команды работают со стеком путей, а значит ты можешь легко возвращаться обратно.pushd /some/path- перейти в каталог и добавить его в стек.popd- вернуться назад по стеку и удалить текущий путь из него.dirs- показать текущий стек директорий.
pushd /etc/nginx
ls -l
pushd /var/log
tail -n 10 syslog
popd # Возврат в /etc/nginx
popd # Возврат туда, где были до первого pushd
Стек хранит историю твоих переходов, как назад в браузере.
dirs -v
# 0 ~/project/noscripts
# 1 ~/project
# 2 ~
Это означает:
dirs +0 → текущий путь
dirs +1 → предыдущий
popd +1 → убрать второй элемент
1. В сложных скриптах, где ты переходишь между 3-4 директориями
2. При автоматизации сборки (build → temp → deploy → назад)
3. Когда нужно "вернуться" точно туда, откуда пришёл
alias bd='popd'
alias pd='pushd'
alias d='dirs -v'
pushd/popd - это просто удобная альтернатива cd с историей. Попробуй - и не можешь не возвращаться к cd ../../../..BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥2
Автоматическая генерация CHANGELOG из git log
Если ты оформляешь релизы или просто хочешь видеть историю изменений красиво, не нужно писать CHANGELOG.md вручную. Bash + git log = автоматическая генерация понятного и читаемого списка коммитов по тегу или дате.
🛠 Простой changelog между тегами
▪️ Пример вывода:
▪️ По дате: за последнюю неделю
▪️ Возможные расширения:
⭐️ Совет: Добавить в Makefile или
И у тебя всегда будет свежий, читаемый список изменений для клиентов или команды.
BashTex📱 #bash
Если ты оформляешь релизы или просто хочешь видеть историю изменений красиво, не нужно писать CHANGELOG.md вручную. Bash + git log = автоматическая генерация понятного и читаемого списка коммитов по тегу или дате.
#!/bin/bash
PREV_TAG=$(git describe --abbrev=0 --tags HEAD^)
CURRENT_TAG=$(git describe --tags)
echo "## Changelog: $PREV_TAG → $CURRENT_TAG" > CHANGELOG.md
git log "$PREV_TAG..$CURRENT_TAG" --pretty="* %s (%an)" >> CHANGELOG.md
## Changelog: v1.2.0 → v1.3.0
* Добавлен скрипт автообновления (admin)
* Фикс логирования ошибок в cron (dev)
* Обновлена документация (docs)
git log --since="7 days ago" --pretty="* %h %s (%an)" > changelog_this_week.md
📍 Группировка по типу коммита (feat, fix, chore)📍 Сортировка по автору или дате📍 Добавление ссылок на GitHub ([#123](https://github.com/...))📍 Генерация changelog на каждый git tag с сохранением в releases/
release.sh:
changelog:
bash noscripts/gen_changelog.sh
И у тебя всегда будет свежий, читаемый список изменений для клиентов или команды.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Автоматическое обновление и перезапуск Docker-контейнеров при выходе новых образов
Если ты используешь докер и хочешь держать свои контейнеры в актуальном состоянии без ручного docker pull + restart - этот пост для тебя. С помощью bash можно отслеживать обновления образа и автоматически перезапускать контейнер, если он устарел.
🌟 Принцип:
🛠 Пример скрипта:
▪️ Для автоматизации: Добавь скрипт в cron или systemd-timer, например, каждые 6 часов:
⭐️ Советы:
BashTex📱 #bash
Если ты используешь докер и хочешь держать свои контейнеры в актуальном состоянии без ручного docker pull + restart - этот пост для тебя. С помощью bash можно отслеживать обновления образа и автоматически перезапускать контейнер, если он устарел.
📍 Проверяем хэш локального и удалённого образа📍 Если разные — обновляем образ📍 Перезапускаем контейнер с теми же параметрами📍 Логируем событие
#!/bin/bash
IMAGE="nginx:latest"
CONTAINER="my-nginx"
LOG="/var/log/docker_autoupdate.log"
echo "[$(date)] Проверка образа $IMAGE" >> "$LOG"
# Получаем текущий локальный digest
LOCAL_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || echo "none")
# Обновляем образ
docker pull "$IMAGE" > /dev/null 2>&1
# Получаем новый digest
NEW_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || echo "none")
# Сравниваем
if [[ "$LOCAL_DIGEST" != "$NEW_DIGEST" ]]; then
echo "[$(date)] Образ обновлён. Перезапуск контейнера $CONTAINER..." >> "$LOG"
docker stop "$CONTAINER"
docker rm "$CONTAINER"
# Запуск с нужными параметрами — укажи свои!
docker run -d --name "$CONTAINER" -p 80:80 "$IMAGE"
echo "[$(date)] Контейнер перезапущен с новым образом." >> "$LOG"
else
echo "[$(date)] Образ актуален. Перезапуск не требуется." >> "$LOG"
fi
0 */6 * * * /usr/local/bin/docker-auto-update.sh
📍 Используй docker inspect для восстановления аргументов запуска, если параметры сложные.📍 Для нескольких контейнеров используй массивы и цикл.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Bash и двоичные данные: читаем, конвертируем, анализируем
Bash - не только для текста. Иногда приходится парсить бинарные файлы, смотреть их содержимое, искать сигнатуры или работать с данными в base64. В арсенале есть несколько утилит:
▪️ xxd - человекочитаемый hex-дамп
Вывод:
Ты сразу видишь:
1. Смещение (слева)
2. HEX-представление
3. ASCII-декод справа (если есть)
Обратно в бинарник:
▪️ od - гибкий дампер
Это дает HEX-дамп без смещений, только байты. Удобно для парсинга в скриптах.
Читаем 2-байтные значения как целые числа.
▪️ base64 - кодирование/декодирование в текст. Когда бинарь нужно «перенести» в текст:
Обратно:
Будет полезно:
- для пересылки двоичных файлов через API
- вставки бинарных данных в JSON/YAML
- генерации payload'ов
▪️ Проверка сигнатур файлов
Для ELF-файлов ожидается:
Можно использовать для определения типа файла без file.
⭐️ Бонус: сравнение бинарников
Выводит байты, которые отличаются, с их смещением.
BashTex📱 #bash #utils
Bash - не только для текста. Иногда приходится парсить бинарные файлы, смотреть их содержимое, искать сигнатуры или работать с данными в base64. В арсенале есть несколько утилит:
xxd, od, base64 - и ты удивишься, сколько они могут.
xxd /bin/ls | head
Вывод:
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0300 3e00 0100 0000 b080 4000 0000 0000 ..>.......@.....
Ты сразу видишь:
1. Смещение (слева)
2. HEX-представление
3. ASCII-декод справа (если есть)
Обратно в бинарник:
xxd -r dump.hex > recovered.bin
od -An -t x1 -v myfile.bin
Это дает HEX-дамп без смещений, только байты. Удобно для парсинга в скриптах.
od -An -t d2 myfile.bin
Читаем 2-байтные значения как целые числа.
base64 /bin/bash > bash.b64
Обратно:
base64 -d bash.b64 > bash_restored
Будет полезно:
- для пересылки двоичных файлов через API
- вставки бинарных данных в JSON/YAML
- генерации payload'ов
head -c 4 somefile | xxd
Для ELF-файлов ожидается:
7f 45 4c 46 → .ELF
Можно использовать для определения типа файла без file.
cmp -l file1.bin file2.bin
Выводит байты, которые отличаются, с их смещением.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8