Пингование списка хостов с журналом доступности в csv/json
Хочешь следить за доступностью нескольких серверов и записывать статистику? Bash + ping + немного магии - и у тебя реестр доступности в csv или json, пригодный для дальнейшего анализа или графиков.
▪️ Пример списка хостов (hosts.txt):
▪️ Скрипт пингует все хосты и сохраняет отчет в CSV:
▪️ Пример вывода ping_log.csv:
▪️ Хочешь в JSON? Добавь это после цикла:
(Понадобится jq, либо можно собрать JSON вручную через echo)
BashTex📱 #bash #utils
Хочешь следить за доступностью нескольких серверов и записывать статистику? Bash + ping + немного магии - и у тебя реестр доступности в csv или json, пригодный для дальнейшего анализа или графиков.
8.8.8.8
1.1.1.1
bashtex.com
192.168.0.1
#!/bin/bash
INPUT="hosts.txt"
OUTPUT="ping_log.csv"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
[[ ! -f "$OUTPUT" ]] && echo "timestamp,host,status,latency_ms" > "$OUTPUT"
while read -r host; do
if [[ -n "$host" ]]; then
PING_OUT=$(ping -c 1 -W 1 "$host" 2>/dev/null)
if [[ $? -eq 0 ]]; then
LATENCY=$(echo "$PING_OUT" | awk -F'=' '/time=/{print $4}' | cut -d' ' -f1)
echo "$DATE,$host,UP,$LATENCY" >> "$OUTPUT"
else
echo "$DATE,$host,DOWN,0" >> "$OUTPUT"
fi
fi
done < "$INPUT"
timestamp,host,status,latency_ms
2025-06-06 12:30:01,8.8.8.8,UP,24.1
2025-06-06 12:30:01,bashtex.com,DOWN,0
jq -Rn '
[inputs | split(",") | {timestamp: .[0], host: .[1], status: .[2], latency_ms: .[3]}]
' "$OUTPUT" > ping_log.json
(Понадобится jq, либо можно собрать JSON вручную через echo)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Автоматическая генерация графиков из логов
Хочешь строить графики без excel и браузеров? Bash +
Рассмотрим: у нас есть csv лог доступности хостов, созданный скриптом мониторинга:
Наша цель: Построить график пинга по времени; сохранить его в png; все сделать из одного bash-скрипта
🛠 Скрипт генерации графика
Если добавить реальный cron - будет наглядная история
🌟 Советы
BashTex📱 #bash #utils
Хочешь строить графики без excel и браузеров? Bash +
gnuplot дают способ визуализировать логи прямо из терминала.Рассмотрим: у нас есть csv лог доступности хостов, созданный скриптом мониторинга:
timestamp,host,status,latency_ms
2025-08-09 12:30:01,8.8.8.8,UP,24.1
2025-08-09 12:31:01,8.8.8.8,UP,25.4
2025-08-09 12:32:01,8.8.8.8,DOWN,0
...
Наша цель: Построить график пинга по времени; сохранить его в png; все сделать из одного bash-скрипта
#!/bin/bash
INPUT="ping_log.csv"
OUTPUT="latency_plot.png"
HOST="8.8.8.8"
# Отфильтровать строки для нужного хоста и подготовить данные
awk -F',' -v host="$HOST" '
$2 == host && $3 == "UP" {
print $1, $4
}
' "$INPUT" > temp_data.dat
# Сгенерировать график
gnuplot <<EOF
set terminal png size 900,300
set output "$OUTPUT"
set title "Latency for $HOST"
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set format x "%H:%M"
set xlabel "Time"
set ylabel "Latency (ms)"
set grid
plot "temp_data.dat" using 1:2 with linespoints title "Ping latency"
EOF
echo "График сохранен в $OUTPUT"
Если добавить реальный cron - будет наглядная история
Можно использовать gnuplot с другими логами: нагрузка CPU, объемы логов, системные метрики;
Можно строить сразу несколько графиков: plot ... title "A", ... title "B";
Поддерживается SVG, PDF, терминал
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👨💻1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁19
Умная упаковка файлов по маске или дате
Сегодня про то, как архивировать файлы выборочно - например, только .log, только старше 3 дней или только те, что совпадают с маской. Будем комбинировать
▪️ Пример 1: Упаковка логов старше 3 дней
▪️ Пример 2: По шаблону имени (например, только report_*.txt)
Упакует все отчеты с именами report_*.txt в архив с датой.
▪️ Если имена с пробелами
▪️ Плюс: Указание имени архива в переменной
BashTex📱 #bash
Сегодня про то, как архивировать файлы выборочно - например, только .log, только старше 3 дней или только те, что совпадают с маской. Будем комбинировать
find, xargs и tar.
find /var/log/myapp -type f -name "*.log" -mtime +3 \
| xargs tar -czf old_logs.tar.gz
find ищет .log, старше 3 днейxargs передаёт списком в tartar упаковывает их в old_logs.tar.gz
find ./reports -type f -name "report_*.txt" \
| xargs tar -czf reports_$(date +%Y%m%d).tar.gz
Упакует все отчеты с именами report_*.txt в архив с датой.
find . -type f -name "*.csv" -print0 \
| xargs -0 tar -czf data.tar.gz
-print0 и -0 защищают от пробелов и спецсимволов.
ARCHIVE="backup_$(date +%F).tar.gz"
find . -type f -name "*.conf" -mtime -7 \
| xargs tar -czf "$ARCHIVE"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Реализация цикла с таймаутом ожидания результата и отменой
Polling с таймаутом в bash - когда нужно подождать результат, но не вечно. Идеально подходит для:
📍 Ожидания ответа от API;
📍 Проверки, появился ли файл;
📍 Проверки, поднялся ли сервис;
📍 Паузы перед перезапуском, если условие не выполнено.
1️⃣ Пример: ждать файл не больше 10 секунд
2️⃣ Пример: проверка доступности порта (через nc)
3️⃣ Более обобщенная функция
▪️ Использование:
Polling pattern с ограничением по времени - инструмент, когда “ожидание результата” должно быть контролируемым.
BashTex📱 #bash #utils
Polling с таймаутом в bash - когда нужно подождать результат, но не вечно. Идеально подходит для:
TIMEOUT=10
INTERVAL=1
FILE="/tmp/ready.flag"
for ((i=0; i<TIMEOUT; i+=INTERVAL)); do
if [[ -f "$FILE" ]]; then
echo "Файл найден"
break
fi
sleep "$INTERVAL"
done
if [[ ! -f "$FILE" ]]; then
echo "Таймаут: файл не появился"
fi
HOST="localhost"
PORT=8080
TIMEOUT=15
for ((i=0; i<TIMEOUT; i++)); do
if nc -z "$HOST" "$PORT"; then
echo "Сервис доступен"
break
fi
sleep 1
done
if ! nc -z "$HOST" "$PORT"; then
echo "Сервис не запустился за $TIMEOUT секунд"
fi
poll_until() {
local timeout=$1
local interval=$2
shift 2
local elapsed=0
while ((elapsed < timeout)); do
if "$@"; then
return 0
fi
sleep "$interval"
((elapsed+=interval))
done
return 1
}
poll_until 10 1 curl -sf https://localhost:8080/health || echo "Недоступен"
Polling pattern с ограничением по времени - инструмент, когда “ожидание результата” должно быть контролируемым.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Генерация временных учёток с автоудалением
Временные учетки в linux с автозапретом - удобный способ:
📍 выдать доступ коллеге или заказчику на пару часов;
📍 дать временный SSH-доступ без ручной чистки;
📍 создать пользователя на ограниченное время (в минутах/часах).
▪️ Пример: учетка на 1 час
▪️ Альтернатива: удаление полностью. Если нужно удалить пользователя, а не только заблокировать:
▪️ Дополнительно: запрет sudo и ограничение SSH
Не добавляйте пользователя в группы типа sudo. Можно ограничить доступ в sshd_config:
▪️ Оборачивание в скрипт
BashTex📱 #bash #security
Временные учетки в linux с автозапретом - удобный способ:
USER="tempuser"
PASS="$(openssl rand -base64 12)"
TIMEOUT_MIN=60
# Создание пользователя
useradd -m "$USER"
echo "$USER:$PASS" | chpasswd
echo "Учетка $USER создана. Пароль: $PASS"
# Блокировка через timeout
echo "passwd -l $USER && echo '[INFO] $USER заблокирован'" | at now + "$TIMEOUT_MIN" minutes
echo "pkill -u $USER; userdel -r $USER" | at now + "$TIMEOUT_MIN" minutes
Не добавляйте пользователя в группы типа sudo. Можно ограничить доступ в sshd_config:
Match User tempuser
ForceCommand echo "Временный доступ завершен"
AllowTcpForwarding no
X11Forwarding no
#!/bin/bash
USER="temp$RANDOM"
PASS="$(openssl rand -base64 10)"
TIMEOUT_MIN=30
useradd -m "$USER"
echo "$USER:$PASS" | chpasswd
echo "Пользователь $USER создан на $TIMEOUT_MIN минут"
echo "Логин: $USER"
echo "Пароль: $PASS"
echo "userdel -r $USER" | at now + "$TIMEOUT_MIN" minutes
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Работа с датами и интервалами времени без внешних утилит
Как работать с датами и временем, если нельзя использовать date, awk, python, jq и т.п. - только встроенные средства? Такое бывает в ограниченных окружениях (initrd, контейнеры, busybox). Что остается? Только POSIX-переменные, арифметика и системный вызов времени через /proc.
▪️ Получение текущего времени в секундах (POSIX timestamp)
Но если доступен Bash ≥ 4.2, можно так:
▪️ Расчет интервала (например, сколько секунд назад)
▪️ Преобразование секунд в формат ЧЧ:ММ:СС
▪️ Проверка "дата в будущем/прошлом"
▪️ Простая "через N секунд"
▪️ Мини-фреймворк времени без date. Если date нет вообще, можно использовать /proc/uptime как источник времени с начала загрузки. Это полезно в init-сценариях и embedded-системах.
Даже без date, python и awk можно: считать интервалы, вычислять прошедшее время, форматировать в ЧЧ:ММ:СС, сравнивать сроки и "таймерить". Это помогает писать portable-скрипты под ограниченные окружения.
BashTex📱 #bash
Как работать с датами и временем, если нельзя использовать date, awk, python, jq и т.п. - только встроенные средства? Такое бывает в ограниченных окружениях (initrd, контейнеры, busybox). Что остается? Только POSIX-переменные, арифметика и системный вызов времени через /proc.
now=$(</proc/uptime) # uptime в секундах с долей
timestamp=$(cut -d. -f1 <<< "$now") # отбрасываем дробную часть
echo "Uptime (сек): $timestamp"
Но если доступен Bash ≥ 4.2, можно так:
now=$(printf '%(%s)T\n' -1) # текущий timestamp
start=1721133000
now=$(printf '%(%s)T\n' -1)
delta=$((now - start))
echo "Прошло $delta секунд"
secs=9384 # Пример: 2 ч, 36 мин, 24 сек
printf -v hh '%02d' $((secs / 3600))
printf -v mm '%02d' $(((secs % 3600) / 60))
printf -v ss '%02d' $((secs % 60))
echo "$hh:$mm:$ss"
deadline=1721190000
now=$(printf '%(%s)T\n' -1)
if (( now > deadline )); then
echo "Просрочено"
else
echo "Еще в сроке"
fi
wait_for=$((60 * 5)) # 5 минут
start=$(printf '%(%s)T\n' -1)
while true; do
now=$(printf '%(%s)T\n' -1)
(( now - start >= wait_for )) && break
sleep 1
done
echo "Прошло 5 минут"
get_now() {
cut -d. -f1 /proc/uptime
}
Даже без date, python и awk можно: считать интервалы, вычислять прошедшее время, форматировать в ЧЧ:ММ:СС, сравнивать сроки и "таймерить". Это помогает писать portable-скрипты под ограниченные окружения.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Отправка файлов на удаленный сервер с логированием и проверкой контрольных сумм
Как надежно передавать файлы на сервер: с логом, контрольной суммой и валидацией? Передача файлов - обычная задача, но часто делается без верификации. Добавим автоматический контроль:
▪️ Инструменты
▪️ Пример: передача и проверка файла
BashTex📱 #bash
Как надежно передавать файлы на сервер: с логом, контрольной суммой и валидацией? Передача файлов - обычная задача, но часто делается без верификации. Добавим автоматический контроль:
scp / rsync - передача
sha256sum - хеши
ssh - удаленное выполнение
logger / лог-файл - аудит
#!/bin/bash
SRC_FILE="/data/backup.tar.gz"
DEST_USER="user"
DEST_HOST="backup.server"
DEST_PATH="/srv/backups/"
LOG="/var/log/file_transfer.log"
FILENAME=$(basename "$SRC_FILE")
CHECKSUM=$(sha256sum "$SRC_FILE" | awk '{print $1}')
STAMP=$(date '+%F %T')
echo "$STAMP : Начата передача $FILENAME" | tee -a "$LOG"
# Отправка файла
scp "$SRC_FILE" "$DEST_USER@$DEST_HOST:$DEST_PATH"
# Проверка хеша на удаленной стороне
REMOTE_SUM=$(ssh "$DEST_USER@$DEST_HOST" "sha256sum '$DEST_PATH/$FILENAME' | awk '{print \$1}'")
# Сравнение и лог
if [[ "$REMOTE_SUM" == "$CHECKSUM" ]]; then
echo "$STAMP : Успешно: $FILENAME передан и проверен" | tee -a "$LOG"
else
echo "$STAMP : Ошибка: контрольные суммы не совпадают!" | tee -a "$LOG"
fi
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤨6😁3
Как красиво ждать с прогрессом в терминале
Иногда скрипту нужно подождать: пауза перед перезапуском сервиса, таймер перед завершением работы, задержка в цикле. Просто sleep - бывает скучно. Сделаем задержку с индикатором прогресса прямо в терминале.
▪️ Вариант 1: простой таймер с индикатором прогресса
Вывод:
▪️ Вариант 2: "бегающий" индикатор во время ожидания
Этот индикатор крутится, пока выполняется команда.
▪️ Вариант 3: таймер обратного отсчета
Это удобно для сценариев с обратным отсчетом до перезапуска или отката.
⭐️ Также можно использовать
BashTex📱 #bash
Иногда скрипту нужно подождать: пауза перед перезапуском сервиса, таймер перед завершением работы, задержка в цикле. Просто sleep - бывает скучно. Сделаем задержку с индикатором прогресса прямо в терминале.
wait_with_progress() {
local seconds=$1
echo -n "Ожидание $seconds сек: ["
for ((i = 0; i < seconds; i++)); do
echo -n "#"
sleep 1
done
echo "] Готово!"
}
wait_with_progress 5
Вывод:
Ожидание 5 сек: [#####] Готово!
spinner_wait() {
local pid=$!
local delay=0.1
local spinstr='|/-\'
echo -n "Ждем... "
while kill -0 $pid 2>/dev/null; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
echo "Готово!"
}
# Пример: запуск команды с ожиданием
(sleep 5) & spinner_wait
Этот индикатор крутится, пока выполняется команда.
countdown() {
local sec=$1
while [ $sec -gt 0 ]; do
printf "\rОсталось: %2d сек..." "$sec"
sleep 1
((sec--))
done
echo -e "\rВремя вышло! "
}
countdown 10
Это удобно для сценариев с обратным отсчетом до перезапуска или отката.
tput civis и tput cnorm для скрытия/показа курсора:
tput civis # скрыть
# ...индикатор...
tput cnorm # вернуть
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11
Построение интерактивного CLI-меню с автодополнением и подсказками
Хотите, чтобы ваши скрипты ощущались как полноценные CLI-утилиты? Добавим в них: интерактивное меню, автодополнение (TAB) и встроенные описания/подсказки по командам.
Создадим скрипт с поддержкой команд (подкоманд) и аргументов, а затем подключаем к нему bash completion через complete -F.
▪️ Пример CLI с командами и подсказками
▪️ Автодополнение через complete -F. Создаем функцию для автодополнения:
Положите этот код в .bashrc или .bash_completion.d/mycli, и автодополнение команд заработает:
▪️ Описание команд при наведении. Если используете bash-completion, можно интегрировать подсказки в стиле:
В более продвинутых реализациях можно добавить справку по каждой команде - через compopt, __ltrim_colon_completions, compgen и массив COMPREPLY.
▪️ Рекомендованная структура CLI
Такой подход с автозагрузкой команд из bin/ позволяет расширять CLI без изменения основного скрипта.
BashTex📱 #bash #utils
Хотите, чтобы ваши скрипты ощущались как полноценные CLI-утилиты? Добавим в них: интерактивное меню, автодополнение (TAB) и встроенные описания/подсказки по командам.
Создадим скрипт с поддержкой команд (подкоманд) и аргументов, а затем подключаем к нему bash completion через complete -F.
#!/usr/bin/env bash
# --- CLI-команды ---
main() {
local cmd="$1"; shift
case "$cmd" in
start) echo "Запуск сервиса" ;;
stop) echo "Остановка сервиса" ;;
status) echo "Статус сервиса" ;;
help|"") show_help ;;
*) echo "Неизвестная команда: $cmd"; show_help ;;
esac
}
# --- Подсказки ---
show_help() {
cat <<EOF
Доступные команды:
start - Запустить сервис
stop - Остановить сервис
status - Показать статус
help - Показать справку
EOF
}
main "$@"
_cli_autocomplete() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
opts="start stop status help"
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
return 0
}
# Подключаем к нашему скрипту
complete -F _cli_autocomplete mycli
Положите этот код в .bashrc или .bash_completion.d/mycli, и автодополнение команд заработает:
$ ./mycli <TAB>
start status stop help
complete -o nospace -o default -F _cli_autocomplete mycli
В более продвинутых реализациях можно добавить справку по каждой команде - через compopt, __ltrim_colon_completions, compgen и массив COMPREPLY.
mycli
├── bin/
│ ├── start
│ ├── stop
│ ├── status
└── mycli
Такой подход с автозагрузкой команд из bin/ позволяет расширять CLI без изменения основного скрипта.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Оптимизация вложенных циклов и массивов
Вложенные циклы в bash - частая причина медленных скриптов при работе с большими массивами и файлами. Особенно если ты обрабатываешь 10000+ элементов и каждый проход делает grep, awk, cut, cat, sed...
▪️ Антипаттерн
➖ Это O(N²). Если массивы по 10к строк - будет 100 млн сравнений.
▪️ Оптимизация через associative array (Bash 4+)
➕ Это уже O(N). И в 1000 раз быстрее.
▪️ Ускорение чтения данных. Избавляемся от cat в цикле:
➖ Плохо:
➕ Лучше:
▪️ Убираем лишние циклы. Когда можно - переноси логику внутрь awk, grep, join, sort -m и т.д.
Пример: пересечение двух файлов без bash-циклов:
BashTex📱 #bash #utils
Вложенные циклы в bash - частая причина медленных скриптов при работе с большими массивами и файлами. Особенно если ты обрабатываешь 10000+ элементов и каждый проход делает grep, awk, cut, cat, sed...
for i in "${list1[@]}"; do
for j in "${list2[@]}"; do
if [[ "$i" == "$j" ]]; then
echo "Match: $i"
fi
done
done
declare -A lookup
# Заполняем хеш
for item in "${list2[@]}"; do
lookup["$item"]=1
done
# Ищем быстро
for i in "${list1[@]}"; do
if [[ ${lookup["$i"]+found} ]]; then
echo "Match: $i"
fi
done
while read line; do
cat "$line"
done < files.txt
mapfile -t files < files.txt
for f in "${files[@]}"; do
cat "$f"
done
Пример: пересечение двух файлов без bash-циклов:
sort file1.txt file2.txt | uniq -d
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Bash-модули: подключение и структура библиотек функций
Когда проект разрастается, скрипты превращаются в мешанину повторяющегося кода. Решение - выносить логику в отдельные .sh-файлы и подключать их как модули. Bash позволяет это делать просто и удобно с помощью source.
▪️ Пример структуры проекта:
▪️ Как подключать:
▪️ Файл
▪️ Файл
▪️ Файл
⭐️ Рекомендации:
BashTex📱 #bash
Когда проект разрастается, скрипты превращаются в мешанину повторяющегося кода. Решение - выносить логику в отдельные .sh-файлы и подключать их как модули. Bash позволяет это делать просто и удобно с помощью source.
project/
├── main.sh
├── lib/
│ ├── colors.sh
│ ├── network.sh
│ └── disk.sh
#!/bin/bash
# main.sh
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/colors.sh"
source "$SCRIPT_DIR/lib/network.sh"
source "$SCRIPT_DIR/lib/disk.sh"
log_info "Начинаем выполнение..."
check_network
check_disk_usage
colors.sh:
#!/bin/bash
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $*"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $*"
}
network.sh:
#!/bin/bash
check_network() {
if ! ping -c1 8.8.8.8 &>/dev/null; then
log_error "Нет подключения к интернету"
else
log_info "Сеть доступна"
fi
}
disk.sh:
#!/bin/bash
check_disk_usage() {
local usage
usage=$(df / | awk 'NR==2 {print $5}')
log_info "Использование диска: $usage"
}
📍 ИспользуйSCRIPT_DIRдля относительных путей (надежно даже из cron);📍 Разделяй модули по темам (log.sh, fs.sh, sys.sh и т.д.);📍 Добавляйset -euo pipefailвmain.sh, но не обязательно в модулях - иначе они могут прерывать подключение.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
Распараллеливание задач с контролем количества потоков
Когда нужно запустить 1000 задач, но не обрушить сервер - важно уметь распараллеливать выполнение с ограничением на количество одновременных процессов. В bash это можно реализовать без внешних утилит вроде parallel.
🌟 Задача: скачать список URL-ов, но не больше N одновременно.
🛠 Пример скрипта:
▪️ Пояснения:
▪️ Когда использовать:
📍 Массовая обработка файлов (сжатие, конвертация).
📍 Сканирование сети.
📍 Пакетные вычисления или API-запросы.
BashTex📱 #bash
Когда нужно запустить 1000 задач, но не обрушить сервер - важно уметь распараллеливать выполнение с ограничением на количество одновременных процессов. В bash это можно реализовать без внешних утилит вроде parallel.
#!/bin/bash
MAX_JOBS=5
URLS_FILE="urls.txt"
semaphore() {
while (( $(jobs -rp | wc -l) >= MAX_JOBS )); do
sleep 0.5
done
}
process_url() {
local url="$1"
echo "[*] Загрузка $url"
curl -s -o /dev/null "$url" && echo "[+] $url OK" || echo "[-] $url FAIL"
}
while read -r url; do
semaphore
process_url "$url" &
done < "$URLS_FILE"
wait
echo "Все задачи завершены"
jobs -rp - выводит только PID активных фоновых задач.semaphore() - блокирует запуск, если уже выполняется $MAX_JOBS процессов.wait в конце - ждет завершения всех фоновых заданий.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Автоматическая отправка отчета об активности crontab-скриптов
Когда скрипты запускаются по cron, часто мы не знаем - сработали ли они, что вывели, были ли ошибки. В результате важная задача могла "молча" упасть, и никто не заметил.
Решение - генерация и отправка ежедневного отчета о выполнении всех cron-задач с логами.
⭐️ Принцип:
📍 Все cron-скрипты логируют вывод в файл.
📍 В конце дня другой скрипт собирает и отправляет логи (по почте, в телегу, в файл).
📍 Старая логика - архивируется или удаляется.
🛠 Пример скрипта:
▪️ Пример cron-задания для скрипта:
▪️ Пример логирования в других скриптах. В каждом cron-скрипте указываем:
✅ Права доступа к логам ограничены: chmod 640, владелец - root или нужный юзер.
✅ Логи очищаются через find или logrotate.
BashTex📱 #bash
Когда скрипты запускаются по cron, часто мы не знаем - сработали ли они, что вывели, были ли ошибки. В результате важная задача могла "молча" упасть, и никто не заметил.
Решение - генерация и отправка ежедневного отчета о выполнении всех cron-задач с логами.
/usr/local/bin/cron-report.sh
#!/bin/bash
LOGDIR="/var/log/cron-jobs"
REPORT="/tmp/cron_report_$(date +%F).log"
echo "Отчет о задачах cron за $(date)" > "$REPORT"
echo "===============================" >> "$REPORT"
for logfile in "$LOGDIR"/*.log; do
echo -e "\n[$(basename "$logfile")]" >> "$REPORT"
tail -n 50 "$logfile" >> "$REPORT"
done
#Отправить отчет (почта или телега)
mail -s "Cron Report $(hostname)" [email protected] < "$REPORT"
#Удаление старых логов старше 7 дней
find "$LOGDIR" -name '*.log' -mtime +7 -delete
0 23 * * * /usr/local/bin/cron-report.sh
#!/bin/bash
# example_job.sh
LOG="/var/log/cron-jobs/example_job.log"
echo "==== $(date) ====" >> "$LOG"
your_command_here >> "$LOG" 2>&1
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
Использование readarray и mapfile для групповой обработки строк
Когда обрабатываем многострочный вывод - часто используем while read, но есть более быстрый способ:
❓ Что делает mapfile? Читает строки из stdin или команды сразу в массив, построчно:
Аналог:
Флаг -t удаляет \n на конце строк.
▪️ Обработка вывода команд:
▪️ Фильтрация и трансформация. Комбинируем с grep, awk, sort, uniq:
▪️ Срезы и подмассивы. Работа с частями:
▪️ Использование с read-only входом:
BashTex📱 #bash #utils
Когда обрабатываем многострочный вывод - часто используем while read, но есть более быстрый способ:
mapfile (синоним - readarray).
mapfile -t lines < input.txt
# теперь ${lines[0]}, ${lines[1]} и т.д. - отдельные строки
Аналог:
readarray -t lines < input.txt
Флаг -t удаляет \n на конце строк.
mapfile -t users < <(cut -d: -f1 /etc/passwd)
for user in "${users[@]}"; do
echo "Пользователь: $user"
done
mapfile -t services < <(systemctl list-units --type=service | awk '/running/ {print $1}')
for svc in "${services[@]}"; do
echo "Активный сервис: $svc"
done
mapfile -t logs < <(tail -n 100 /var/log/syslog)
# последние 5 строк
printf '%s\n' "${logs[@]: -5}"
some_func() {
local lines=()
mapfile -t lines
echo "Прочитано строк: ${#lines[@]}"
}
cat /etc/passwd | some_func
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Упаковка структуры каталогов с фильтрацией
Когда нужно архивировать не весь каталог, а только часть - с фильтрацией и даже переименованием путей внутри архива - на помощь приходят
▪️ Базовый пример: фильтруем по маске и архивируем
Тут мы архивируем только .conf-файлы.
▪️ Добавим переименование путей внутри архива. Архивируем все из src/, но хотим, чтобы внутри архива это лежало как app/.
▪️ Упаковка через find + --transform + относительные пути. Предположим, хотим архивировать только .sh и .py-файлы, заменив scripts/ на bin/ внутри архива:
▪️ Упрощенный однострочник:
▪️ Продвинутый пример: исключения + трансформация + директория
BashTex📱 #bash #utils
Когда нужно архивировать не весь каталог, а только часть - с фильтрацией и даже переименованием путей внутри архива - на помощь приходят
find, tar и его флаг --transform.
find project/ -type f -name "*.conf" > list.txt
tar -czf config_backup.tar.gz -T list.txt
Тут мы архивируем только .conf-файлы.
tar -czf app.tar.gz \
--transform='s|^src|app|' \
-C ./ src
--transform использует sed-подобные выражения. Тут s|^src|app| означает: заменить в начале пути src на app.
find scripts/ -type f \( -name "*.sh" -o -name "*.py" \) > filelist.txt
tar -czf bin_scripts.tar.gz \
--transform='s|^scripts|bin|' \
-T filelist.txt
find scripts/ -type f -name "*.sh" \
| tar -czf archive.tar.gz --transform='s|^scripts|bin|' -T -
find ./src -type f ! -name "*.tmp" \
| tar -czf src_clean.tar.gz \
--transform='s|^./src|clean_src|' \
-T -
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Планировщик задач с временными окнами: только ночью, только по будням, только в выходные
Иногда cron не подходит:
📍 нужно запустить задачу в определенное время суток,
📍 но не строго по расписанию, а если есть что обрабатывать,
📍 и не запускать ее днем, когда сервер под нагрузкой.
Тут пригодится встроенная проверка временных окон в скрипте, а cron пусть просто каждые 10 минут запускает "умный планировщик".
🛠 Пример: выполнение задачи только с 02:00 до 05:00 по будням
▪️ Расширение: исключение праздников (по файлу)
▪️ Альтернатива: запуск только по выходным с 3 до 6 утра
▪️ Запуск через cron
BashTex📱 #bash #utils
Иногда cron не подходит:
Тут пригодится встроенная проверка временных окон в скрипте, а cron пусть просто каждые 10 минут запускает "умный планировщик".
#!/bin/bash
#настройки временного окна
start_hour=2
end_hour=5
# день недели (1..5 = пн-пт)
dow=$(date +%u)
#часы сейчас
hour=$(date +%H)
#проверка: будний день и нужное время
if (( dow >= 1 && dow <= 5 )) && (( hour >= start_hour && hour < end_hour )); then
echo "[$(date)] Временное окно открыто. Выполняем задачу."
#здесь реальная задача:
/opt/backup/backup-db.sh
else
echo "[$(date)] Вне временного окна. Пропуск."
fi
holiday_file="/etc/holidays.txt"
today=$(date +%Y-%m-%d)
if grep -q "$today" "$holiday_file"; then
echo "Сегодня праздник. Задача не выполняется."
exit 0
fi
(( dow == 6 || dow == 7 )) && (( hour >= 3 && hour < 6 )) && run_task
*/10 * * * * /usr/local/bin/task_scheduler.sh >> /var/log/task.log 2>&1
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10
Печать таблиц с автошириной и выравниванием
column, awk, printf - минимализм, читаемость и стиль без excel и pandas. Bash-скрипты часто выводят списки, но без форматирования:
Вывод «прыгает» - неудобно читать. Решаем с помощью:
column - автоширина и выравнивание
awk - гибкая фильтрация и формат
printf - точный контроль длины столбцов
▪️ Быстрое решение: column -t
Результат:
-t = "табличный режим", разбивает по пробелам, автоширина.
▪️ Альтернатива: awk с выравниванием
Результат:
Плюсы:
Точное выравнивание;
Подходит для чисел, выравненных по правому краю (%6s, %6d).
▪️ Автоматизация с массивом и printf
▪️ Таблица из файла CSV
-s, - задает разделитель (запятая), -t - табличный вид.
BashTex📱 #bash
column, awk, printf - минимализм, читаемость и стиль без excel и pandas. Bash-скрипты часто выводят списки, но без форматирования:
echo "user1 1234 active"
echo "user10 99 disabled"
Вывод «прыгает» - неудобно читать. Решаем с помощью:
column - автоширина и выравнивание
awk - гибкая фильтрация и формат
printf - точный контроль длины столбцов
#!/bin/bash
echo -e "USER ID STATUS\nuser1 1234 active\nuser10 99 disabled" | column -t
Результат:
USER ID STATUS
user1 1234 active
user10 99 disabled
-t = "табличный режим", разбивает по пробелам, автоширина.
awk '{ printf "%-10s %-6s %-10s\n", $1, $2, $3 }' <<< "user1 1234 active
user10 99 disabled"
Результат:
user1 1234 active
user10 99 disabled
Плюсы:
Точное выравнивание;
Подходит для чисел, выравненных по правому краю (%6s, %6d).
header=("USER" "ID" "STATUS")
rows=(
"user1 1234 active"
"user10 99 disabled"
"admin 5678 maintenance"
)
{
printf "%-10s %-6s %-12s\n" "${header[@]}"
for row in "${rows[@]}"; do
printf "%-10s %-6s %-12s\n" $row
done
} | column -t
column -s, -t < users.csv
-s, - задает разделитель (запятая), -t - табличный вид.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12
Please open Telegram to view this post
VIEW IN TELEGRAM
😁20🔥1
Авторазрешение зависимостей скрипта через dynamic sourcing
В больших bash-проектах часто есть несколько вспомогательных файлов (.sh или .bash), которые содержат функции и настройки. Проблема в том, что:
📍 Скрипт может запуститься в другом каталоге - пути сломаются
📍 Некоторые модули могут отсутствовать или лежать в нестандартных местах
📍 При изменении структуры проекта придётся вручную переписывать source
Решение: динамическое подключение модулей
1️⃣ Автоматический source по списку зависимостей
Такой подход позволяет легко добавлять новые пути в поиск - модуль подтянется сам.
2️⃣ Dynamic sourcing по зависимостям из конфигурации. Можно вынести список зависимостей в отдельный файл deps.txt:
А в скрипте:
3️⃣ Поиск относительно текущего скрипта. Чтобы скрипт работал из любого места:
▪️ Плюсы подхода:
✅ Нет жестких путей;
✅ Можно запускать в разных окружениях;
✅ Удобно для open-source проектов и shared-библиотек;
✅ Легко расширять - просто добавь файл в deps.txt.
BashTex📱 #bash
В больших bash-проектах часто есть несколько вспомогательных файлов (.sh или .bash), которые содержат функции и настройки. Проблема в том, что:
Решение: динамическое подключение модулей
#!/bin/bash
set -e
# Список модулей, которые нужны для работы
modules=("logger.sh" "utils.sh" "net.sh")
# Каталоги для поиска
search_paths=(
"$PWD/lib"
"$PWD/modules"
"/usr/local/share/myscript"
)
for mod in "${modules[@]}"; do
found=0
for path in "${search_paths[@]}"; do
if [[ -f "$path/$mod" ]]; then
source "$path/$mod"
echo "[OK] Loaded $mod from $path"
found=1
break
fi
done
if (( !found )); then
echo "[ERROR] Module $mod not found" >&2
exit 1
fi
done
Такой подход позволяет легко добавлять новые пути в поиск - модуль подтянется сам.
logger.sh
utils.sh
net.sh
А в скрипте:
while IFS= read -r dep; do
found=0
for path in "${search_paths[@]}"; do
if [[ -f "$path/$dep" ]]; then
source "$path/$dep"
found=1
break
fi
done
(( found )) || { echo "[MISSING] $dep" >&2; exit 1; }
done < deps.txt
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/logger.sh"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4