es
Feedback
BashTex | Linux

BashTex | Linux

Ir al canal en Telegram

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

Mostrar más
2 518
Suscriptores
+124 horas
-67 días
-130 días
Archivo de publicaciones
Как безопасно обрабатывать файлы с пробелами в именах Файлы с пробелами, табами и спецсимволами - классическая причина мистических багов в bash. Скрипт вроде работает… пока не встретит файл типа: my file.txt или backup (old).tar.gzАнти-паттерн

for f in $(ls); do
  echo "$f"
done
Проблема: bash режет вывод по пробелам и переводам строк. Файл my file.txt превратится в два разных слова. ➕ Правильный способ №1 - glob + кавычки

for f in *; do
  echo "$f"
done
Почему это безопаснее: * раскрывается самим shell; каждый элемент цикла - это отдельное имя файла; кавычки сохраняют пробелы. Если нужен определённый тип:

for f in *.log; do
  [[ -e "$f" ]] || continue
  echo "$f"
done
[[ -e "$f" ]] защищает, если совпадений нет. ➕ Правильный способ №2 - find -print0. Для рекурсивного обхода:

find . -type f -print0 | while IFS= read -r -d '' f; do
  echo "$f"
done
Почему это хорошо: -print0 разделяет файлы нулевым байтом; это безопасно даже для пробелов, табов и спецсимволов; read -d '' читает до NUL, а не до пробела. ▪️ Безопасная передача в xargs

find . -type f -print0 | xargs -0 rm -f
Пара: -print0 и xargs -0 должны идти вместе. BashTex 📱 #bash #utils

Brace expansion для массовых операций Brace expansion - это встроенная фича, которая позволяет генерировать списки прямо в командной строке. Работает быстро, читаемо и без лишних for. ▪️ Диапазоны чисел

echo {1..5}

1 2 3 4 5
С шагом:

echo {1..10..2}

1 3 5 7 9
▪️ Диапазоны букв

echo {a..e}

a b c d e
▪️ Массовое создание файлов

touch file_{1..5}.txt
Создаст:

file_1.txt
file_2.txt
...
▪️ Создание каталогов

mkdir -p project/{src,bin,config,logs}
Результат:

project/src
project/bin
project/config
project/logs
▪️ Комбинирование

echo {dev,prod}_{1..3}

dev_1 dev_2 dev_3 prod_1 prod_2 prod_3
▪️ Практика: быстрые шаблоны. Создать структуру окружений

mkdir -p env/{dev,stage,prod}/{logs,tmp,data}
Создать пачку логов

touch log_{2024..2026}_{01..12}.log
Удаление группы файлов

rm file_{1..10}.txt
⚠️ Важный момент. Brace expansion происходит до выполнения команды. Это не цикл и не glob. Например:

echo file_{1..3}.txt
сначала превращается в:

echo file_1.txt file_2.txt file_3.txt
BashTex 📱 #bash #utils

Автоматическая очистка старых systemd-журналов systemd-journal удобен, но есть проблема - логи могут занять гигабайты диска, особенно на загруженных серверах. ▪️ Сколько сейчас занимают журналы

journalctl --disk-usage

Archived and active journals take up 2.3G on disk
▪️ Очистка по размеру. Оставить, например, не больше 500 МБ:

journalctl --vacuum-size=500M
Удалятся самые старые записи, пока объем не станет ~ 500 МБ. ▪️ Очистка по времени. Оставить только последние 7 дней:

journalctl --vacuum-time=7d
Поддерживаются: d - дни h - часы m - минуты
▪️ Комбинированный подход. Часто используют оба ограничения:

journalctl --vacuum-time=7d
journalctl --vacuum-size=1G
Это дает контроль и по времени, и по размеру. ▪️ Добавление в cron

0 3 * * * /usr/bin/journalctl --vacuum-time=7d --vacuum-size=1G
▪️ Постоянная настройка через journald. Чтобы не чистить вручную:

/etc/systemd/journald.conf
Пример:

SystemMaxUse=1G
SystemKeepFree=500M
MaxRetentionSec=7day
После изменения:

systemctl restart systemd-journald
BashTex 📱 #bash

Как работать с большими файлами без загрузки в память Частая ошибка: пытаться обработать большой файл, загружая его целиком в память. Например:

content=$(cat huge.log)
Если файл весит несколько гигабайт - скрипт может съесть всю RAM или просто упасть. Правильный подход - обрабатывать файл потоково. ▪️ Чтение файла построчно. Самый безопасный способ:

while IFS= read -r line; do
    echo "$line"
done < huge.log
файл читается строка за строкой; память почти не используется; можно обрабатывать очень большие файлы. ▪️ Использование grep / awk. Unix-утилиты работают потоково, поэтому идеально подходят для больших файлов. Например:

grep ERROR huge.log
или:

awk '/ERROR/ {print $0}' huge.log
Они читают файл частями, не загружая его полностью. ▪️ Анализ логов. Быстрый пример анализа:

grep ERROR huge.log | awk '{print $5}' | sort | uniq -c
Это обработает гигабайтные логи за секунды. ▪️ tail для живых логов. Если файл постоянно растет:

tail -F huge.log
Можно фильтровать сразу:

tail -F huge.log | grep ERROR
Это удобно для мониторинга сервисов. ▪️ Чтение файла частями. Иногда нужно обрабатывать батчами:

split -l 100000 huge.log part_
Файл разобьется на куски:

part_aa
part_ab
part_ac
Теперь их можно обрабатывать параллельно. BashTex 📱 #bash #utils

Использование /dev/null правильно /dev/null - это специальное устройство в linux, которое принимает любые данные и просто их выбрасывает. Часто используется, когда нужно убрать лишний вывод команд. ▪️ Отключаем stdout. Если команда выводит много информации:

ls /tmp > /dev/null
Теперь stdout (fd 1) будет игнорироваться. ▪️ Отключаем только ошибки. Если нужно скрыть stderr (fd 2):

ls /no/such/file 2> /dev/null
Ошибки исчезнут, но нормальный вывод останется. ▪️ Полное подавление вывода. Иногда нужно убрать все:

command > /dev/null 2>&1
Что происходит: stdout в /dev/null и stderr туда же ▪️ Пример:

curl -s https://bashtex.com > /dev/null 2>&1
Команда выполняется тихо. ▪️ Проверка команды без мусора. Полезный паттерн:

command -v docker > /dev/null 2>&1
Проверяем наличие команды:

if command -v docker > /dev/null 2>&1; then
    echo "Docker установлен"
fi
🤩 Частая ошибка. Некоторые пишут:

command 2>&1 > /dev/null
Это не то же самое. Правильный порядок:

command > /dev/null 2>&1
Потому что редиректы выполняются слева направо. ▪️ Практические кейсы. Проверка файла

test -f file.txt > /dev/null 2>&1
Проверка сервиса

systemctl is-active nginx > /dev/null
Проверка сети

ping -c1 google.com > /dev/null 2>&1
BashTex 📱 #bash #utils

Нет времени объяснять, накатывай Linux BashTex 📱 #юмор
Нет времени объяснять, накатывай Linux BashTex 📱 #юмор

Проверка, какие сервисы стартуют дольше всего Если сервер долго загружается, проблема часто не в системе в целом, а в одном-двух медленных сервисах. В systemd есть встроенный инструмент для такой диагностики - systemd-analyze. ▪️ Смотрим самые медленные сервисы. Самая полезная команда:

systemd-analyze blame
Пример вывода:

8.532s docker.service
4.921s networkd-wait-online.service
3.102s postgresql.service
1.876s nginx.service
Список уже отсортирован по времени запуска. Что это значит: docker.service запускался 8.5 секунд networkd-wait-online.service ждал сеть почти 5 секунд Именно такие сервисы чаще всего замедляют загрузку. ▪️ Смотрим цепочку зависимостей. Иногда сервис запускается быстро, но ждет другой сервис. Проверить можно так:

systemd-analyze critical-chain
Пример:

graphical.target
└─docker.service
  └─network-online.target
    └─systemd-networkd-wait-online.service
Это показывает кто кого блокирует при загрузке. ▪️ Общая статистика загрузки. Полезная команда:

systemd-analyze
Пример:

Startup finished in 3.112s (kernel)
                + 9.842s (userspace)
Здесь видно: время загрузки ядра время загрузки systemd сервисов ▪️Частые причины медленной загрузки. Чаще всего тормозят: networkd-wait-online.service docker.service snapd.service базы данных storage-сервисы Иногда сервис ждет ресурс, который ему не нужен. BashTex 📱 #linux #utils

В России можно посещать IT-мероприятия хоть каждый день: как оффлайн, так и онлайн Но где их находить? Как узнавать о них ран
В России можно посещать IT-мероприятия хоть каждый день: как оффлайн, так и онлайн Но где их находить? Как узнавать о них раньше, чем когда все начнут выкладывать фотографии оттуда? Переходите на канал IT-Мероприятия России. В нём каждый день анонсируются мероприятия со всех городов России 📆 в канале размещаются как онлайн, так и оффлайн мероприятия; 👩‍💻 можно найти ивенты по любому стеку: программирование, frontend-backend разработка, кибербезопасность, дата-аналитика, osint, devops и другие; 🎙 разнообразные форматы мероприятий: митапы с коллегами по цеху, конференции и вебинары с известными опытными специалистами, форумы и олимпиады от важных представителей индустрии и многое другое А чтобы не искать по разным форумам и чатам новости о предстоящих ивентах: 🚀 IT-мероприятия Россииподписывайся и будь в курсе всех предстоящих мероприятий!

Современный мониторинг ресурсов Если стандартный top кажется неудобным, а htop - уже привычным, стоит попробовать btop. Это современный мониторинг ресурсов с удобным интерфейсом и большим количеством полезных функций. ▪️ Что показывает btop. В одном окне можно увидеть: загрузку CPU по ядрам использование RAM и swap дисковую активность сетевой трафик список процессов с сортировкой Интерфейс обновляется в реальном времени и выглядит значительно понятнее, чем классические инструменты. ▪️ Установка

sudo apt install btop # Ubuntu / Debian
sudo dnf install btop # RHEL / CentOS / Fedora
sudo pacman -S btop # Arch
▪️ Запуск:

btop
🤩 Что делает его удобным Интерактивный список процессов Можно: сортировать по CPU / RAM убивать процессы фильтровать список ▪️ Клавиши: F9 - kill process F6 - сортировка F - поиск процесса ▪️ Мониторинг сети. btop показывает: входящий / исходящий трафик скорость сети активность интерфейсов Это удобно, когда нужно быстро понять куда уходит трафик. ▪️ Наглядная нагрузка CPU. В отличие от top, здесь видно: загрузку каждого ядра историю нагрузки spikes CPU Очень полезно при диагностике перегрузки сервера. ▪️ Полезные настройки Открыть настройки: ESC Можно изменить: тему интерфейса частоту обновления отображаемые графики сетевые интерфейсы Конфиг хранится в:

~/.config/btop/btop.conf
BashTex 📱 #linux #monitoring

Контроль превышения лимитов ulimit у сервисов Сервис падает без причины, но в логах странные ошибки:
Too many open files Resource temporarily unavailable fork: retry cannot allocate memory
Очень часто это не баг. Это лимиты ulimit. ▪️ Какие лимиты критичны 1️⃣ nofile - открытые файлы. Сколько файловых дескрипторов может открыть процесс. Проверка:

ulimit -n
Или для конкретного процесса:

cat /proc/<PID>/limits | grep "Max open files"
Если видишь 1024, то для прод-сервиса это почти всегда мало. 2️⃣ nproc - количество процессов. Ограничение на число процессов пользователя. Проверка:

ulimit -u

Или:


cat /proc/<PID>/limits | grep "Max processes"

Если приложение активно форкает воркеры - лимит может убить его.

🤩
 
Почему это сложно заметить


сервис стартует нормально
падает только под нагрузкой
в логах нет прямого указания на лимит
systemd может перезапускать бесконечно

▪️
 
Проверка лимитов у systemd-сервиса



systemctl show myservice | grep -E 'LimitNOFILE|LimitNPROC'

Если пусто, то используются дефолтные значения системы.

▪️
 Как исправить
. Создать override:


systemctl edit myservice

Добавить:


[Service]
LimitNOFILE=65535
LimitNPROC=4096

Перезагрузить:


systemctl daemon-reload
systemctl restart myservice

▪️
 Быстрая диагностика падений
. Если сервис падает под нагрузкой:

Проверить 
/proc/<PID>/limits

Посмотреть количество открытых файлов:


ls /proc/<PID>/fd | wc -l

Проверить количество процессов пользователя:


ps -u username | wc -l
BashTex 📱 #bash #check

🖥️ Выбираешь сервер под ИИ? Сначала загляни сюда 23 апреля в 11:00 (МСК) — бесплатный вебинар от CNS: «Как выбрать сервер дл
🖥️ Выбираешь сервер под ИИ? Сначала загляни сюда 23 апреля в 11:00 (МСК) — бесплатный вебинар от CNS: «Как выбрать сервер для ИИ в 2026 году: GPU, TCO и подводные камни» Если ты сейчас разбираешься, что брать под LLM, инференс или RAG — этот час сэкономит тебе кучу времени, нервов и, возможно, бюджета. Что разберём: 🔹 NVIDIA Hopper vs Blackwell — в чём реальная разница под задачи 2026 года, и не переплачиваешь ли ты за архитектуру 🔹 TCO без иллюзий — как считать полную стоимость владения, где прячутся скрытые расходы 🔹 Типичные ошибки при закупке GPU-серверов — скрытые ловушки и как грамотно сопоставить характеристики железа с реальными задачами нейросетей 🔹 Q&A-сессия — спрашивай, отвечаем честно Кому это полезно: — IT-директорам — Архитекторам и администраторам инфраструктуры — Всем, кто строит или планирует on-prem под ML/LLM/RAG 🗓 23 апреля, 11:00–12:00 МСК 📌 Регистрация: webinar.cns-corp.ru #реклама О рекламодателе

Работа с дескрипторами файлов В linux все - это файл. И каждый процесс работает с файловыми дескрипторами: 0 - stdin 1 - stdout 2 - stderr 3+ - любые дополнительные Понимание этого - ключ к нормальной автоматизации. ▪️ Базовые перенаправления

command >out.log        # stdout
command 2>err.log       # stderr
command >all.log 2>&1   # объединить
2>&1 значит: направь stderr туда же, куда сейчас смотрит stdout. ⚠️ Порядок важен: command 2>&1 >file - НЕ то же самое. ▪️ Dup (дублирование дескрипторов). Можно создать свой поток:

exec 3>debug.log
echo "debug" >&3
Теперь 3 пишет в debug.log. Это удобно, если нужно: отделить debug-лог от основного вывода не засорять stdout вести параллельный лог ▪️ Временное перенаправление

{
  echo "только в файл"
} >file.txt
Или:

exec >all_output.log 2>&1
Теперь весь скрипт пишет в лог. ▪️ Закрытие дескриптора. Иногда нужно закрыть поток:

exec 3>&-
Это освобождает дескриптор. Полезно при работе с сокетами, FIFO и временными логами. ▪️ Практический кейс. Раздельный лог и чистый stdout:

exec 3>debug.log
BASH_XTRACEFD=3
set -x
Трассировка уйдет в файл, а stdout останется чистым для пайплайна. BashTex 📱 #bash #utils

Спалили BashTex 📱 #юмор
Спалили BashTex 📱 #юмор

Почему cron не сработал Каждый админ хотя бы раз слышал: Cron не отработал. Но, спойлер: в 90% случаев cron работает. Не работает: окружение, путь или логика скрипта. 1️⃣ Неправильный PATH. Cron запускается с минимальным окружением. То, что работает в shell:

myscript.sh
В cron может не найти: command not found Проверка:

echo $PATH
Решение:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Или использовать абсолютные пути:

/usr/bin/rsync
/usr/bin/docker
2️⃣ Не тот пользователь. Есть:

crontab -e
И есть:

sudo crontab -e
Это два разных crontab. Проверка:

crontab -l
sudo crontab -l
Иногда задача просто стоит не там. 3️⃣ Нет прав на файл. Скрипт есть. Но:

chmod +x script.sh
забыли. Или владелец не тот. 4️⃣ Неправильный shebang. Если в начале:

#!/bin/bash
А на системе bash лежит в:

/usr/bin/bash
Cron молча свалится. Проверка:

which bash
Лучший вариант:

#!/usr/bin/env bash
5️⃣ Нет логирования и кажется, не сработал Если вывод не перенаправлен, ты его не увидишь. Правильно:

0 3 * * * /path/script.sh >> /var/log/script.log 2>&1
Без этого ты гадаешь. 6️⃣ Разница окружения. Cron не знает: твоих alias твоих переменных твоего virtualenv твоего nvm Если работает вручную, но не в cron - почти всегда проблема в ENV. Debug-метод:

env > /tmp/cron_env.txt
7️⃣ Скрипт падает внутри. Cron сработал. Но внутри:

rm -rf "$DIR"
где $DIR пустой. Без:

set -euo pipefail
ошибка могла остаться незамеченной. 8️⃣ Cron вообще не запущен. Редко, но бывает. Проверка:

systemctl status cron
# или
systemctl status crond
BashTex 📱 #cron

Спалили BashTex 📱 #юмор
Спалили BashTex 📱 #юмор

Sync tricks: инкременты, hard links и бэкапы Все знают про rsync, но не все используют его на 100%. Сегодня разберем три мощных приема: инкрементальные бэкапы, hard links для экономии места и атомарная схема снапшотов 1️⃣ Инкрементальный sync. База:

rsync -a --delete /data/ /backup/current/
Что происходит: -a - сохраняет права, владельца, время --delete - удаляет лишнее в приемнике Это зеркало. Но это не история. Каждый запуск перезаписывает прошлый бэкап. 2️⃣ Настоящие снапшоты через hard links. Допустим, структура такая:

/backup/
 ├── 2026-03-29/
 ├── 2026-03-30/
 └── 2026-03-31/
Команда:

TODAY=$(date +%F)
YESTERDAY=$(date -d "yesterday" +%F)

rsync -a --delete \
  --link-dest=/backup/$YESTERDAY \
  /data/ /backup/$TODAY/
Что происходит: изменённые файлы - копируются неизмененные - создаются как hard link места занимает почти как один бэкап Что тут необычного? Hard link - это не копия файла. Это второе имя для того же inode. Проверка:

ls -li file1 file2
Одинаковый inode - это один и тот же файл. Удаляешь снапшот 29-го числа и файл не удалится, если он есть в 30-м. Здесь же и начинается экономия места. Если данные почти не меняются: 30 снапшотов могут занимать +5–10% к объему, вместо ×30 бэкапов. Это почти как ZFS snapshots, но работает на обычном ext4. 3️⃣ Атомарная схема без битых бэкапов. Никогда не пиши прямо в конечную папку. Правильно:

rsync -a --delete \
  --link-dest=/backup/$YESTERDAY \
  /data/ /backup/.tmp-$TODAY/ &&
mv /backup/.tmp-$TODAY /backup/$TODAY
Теперь: если rsync упал - снапшот не появится всегда либо полный, либо отсутствует 4️⃣ Ротация снапшотов. Храним 14 дней:

find /backup -maxdepth 1 -type d -mtime +14 -exec rm -rf {} \;
(Осторожно с путями.) 🛠 Мини-скрипт

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

SRC="/data"
DST="/backup"
TODAY=$(date +%F)
YESTERDAY=$(ls -1 $DST | sort | tail -n 1)

rsync -a --delete \
  ${YESTERDAY:+--link-dest=$DST/$YESTERDAY} \
  "$SRC/" "$DST/.tmp-$TODAY/"

mv "$DST/.tmp-$TODAY" "$DST/$TODAY"
Первый запуск - обычная копия. Все следующие - инкременты. BashTex 📱 #bash #backup

Не все так просто, кожаный BashTex 📱 #юмор
Не все так просто, кожаный BashTex 📱 #юмор

Автоматический failover при недоступности mount-точки Неприятная ситуация когда mount вроде есть, но по факту хранилище уже умерло. NFS отвалился. iSCSI завис. Ceph не отвечает. Сервис продолжает писать… в никуда. Решение - автоматическая логика: Проверка -> попытка remount -> переключение на fallback. ▪️ Логика failover Проверяем, что mount существует; Проверяем доступность записи; Если ошибка, то пробуем remount; Если не помогло - переключаемся на fallback. 🛠 Пример скрипта

#!/usr/bin/env bash

MOUNT_POINT="/data"
FALLBACK="/data_local"
TEST_FILE="$MOUNT_POINT/.healthcheck"

log() {
  echo "$(date '+%F %T') | $1"
}

check_mount() {
  mountpoint -q "$MOUNT_POINT" || return 1
  timeout 3 touch "$TEST_FILE" 2>/dev/null || return 1
  rm -f "$TEST_FILE"
}

remount() {
  log "Попытка remount..."
  mount -o remount "$MOUNT_POINT"
}

switch_to_fallback() {
  log "Переключение на fallback $FALLBACK"
  umount -l "$MOUNT_POINT"
  mount --bind "$FALLBACK" "$MOUNT_POINT"
}

main() {
  if check_mount; then
    log "Mount работает нормально"
    exit 0
  fi

  log "Mount недоступен"

  remount && sleep 2

  if check_mount; then
    log "Remount помог"
    exit 0
  fi

  switch_to_fallback
}

main
▪️ Что здесь важно 1. timeout - если NFS завис, без timeout скрипт повиснет навсегда. 2. mountpoint -q - Проверяет именно mount, а не просто директорию. 3. umount -l - lazy umount - полезно, если есть залипшие процессы. ▪️ Как запускать правильно Лучше всего: systemd timer или healthcheck внутри сервиса или отдельный watchdog unit ⚠️ Нюансы Если сервис пишет активно, то нужно ставить его на паузу перед failover; fallback должен быть заранее подготовлен; важно логировать переключения; нужен механизм возврата обратно. BashTex 📱 #bash #utils

Профилирование bash-скрипта Большинство bash-скриптов медленные не потому что bash плохой, а потому что внутри: лишние grep | awk | sed, десятки subshell, сетевые вызовы без таймаутов и циклы по 100k строк И пока не измерил - не оптимизируешь. 1️⃣ Базовый уровень - time. Самое простое:

time ./script.sh
Вывод:

real    0m3.421s
user    0m0.212s
sys     0m0.084s
Что важно: real - общее время (включая ожидание сети, IO) user - CPU в user space sys - системные вызовы
Если real > user + sys - это значит, что скрипт ждет (сеть, диск, sleep). Если user большой - это значит много вычислений. 2️⃣ Профилирование построчно через DEBUG trap. Настоящая магия начинается здесь.

#!/usr/bin/env bash

PS4='+ $(date "+%s.%N") '
exec 3>&2
BASH_XTRACEFD=3
set -x
Но это просто трассировка. Чтобы измерять время между строками:

#!/usr/bin/env bash

last_time=$(date +%s%N)

trap '
  now=$(date +%s%N)
  diff=$(( (now - last_time) / 1000000 ))
  echo "${diff} ms → $BASH_COMMAND"
  last_time=$now
' DEBUG
Теперь перед каждой командой будет вывод:

2 ms → var=$(cat file)
153 ms → curl https://api
1 ms → echo done
И сразу видно: где реальная задержка, какой вызов тормозит и сколько стоит subshell ⚠️ Важно trap DEBUG вызывается перед каждой командой, включая: внутренние, подстановки и циклы. На больших скриптах лог будет огромный. ▪️ Мини-профилировщик функции. Если нужно измерить только конкретный блок:

measure() {
  local start=$(date +%s%N)
  "$@"
  local end=$(date +%s%N)
  echo "Функция заняла $(( (end - start)/1000000 )) ms"
}
Использование:

measure heavy_function
BashTex 📱 #bash #utils

Почему sleep - это костыль? Очень часто используют такую конструкцию:

curl https://api.bashtex.com || sleep 5 && curl https://api.bashtex.com
Или ещё хуже: в цикле с фиксированной паузой. Это неуправляемый retry, который: создает лишнюю нагрузку, не учитывает тип ошибки, не масштабируется и может устроить небольшой DDoS при массовом падении сервиса. Правильный подход - retry с exponential backoff. ▪️ Почему sleep 5 - это плохая стратегия. Представим: API лежит 2 минуты. 100 серверов начинают делать: запрос -> sleep 5 -> запрос -> sleep 5 → … Ты получаешь синхронную атаку на уже мертвый сервис. Exponential backoff делает паузы все длиннее: 1s -> 2s -> 4s -> 8s -> 16s -> ... Это: снижает нагрузку, дает сервису восстановиться, уменьшает каскадные падения 🛠 Базовая retry-обертка

retry() {
  local max_attempts=$1
  shift

  local attempt=1
  local delay=1

  while true; do
    "$@" && return 0

    if (( attempt >= max_attempts )); then
      echo "Команда не удалась после $attempt попыток"
      return 1
    fi

    echo "Попытка $attempt неудачна. Повтор через $delay сек."
    sleep "$delay"

    attempt=$(( attempt + 1 ))
    delay=$(( delay * 2 ))
  done
}
▪️ Использование:

retry 5 curl -fsS https://api.bashtex.com
▪️ Что здесь происходит "$@" - передаем любую команду; выходной код управляет retry; задержка удваивается; максимум попыток ограничен. ▪️ Когда retry вреден при логических ошибках (401, 403); если операция не идемпотентна; если сервис возвращает fatal error. Retry должен применяться к временным ошибкам, а не ко всем подряд. BashTex 📱 #bash #utils