Меньше if и больше логики в одну строку
Когда вы пишете:
В мире плачет один котенок…🥺 Ведь есть куда более лаконичная альтернатива:
Это логические цепочки (&& и ||), которые позволяют писать коротко и эффективно.
▪️ Принцип short-circuit логики
Bash, как и многие языки, останавливает выполнение цепочки, если уже ясно, что дальше не нужно:
cmd1 && cmd2 - cmd2 выполняется только если cmd1 завершилась успешно (exit 0).
cmd1 || cmd2 - cmd2 выполняется только если cmd1 завершилась с ошибкой (exit ≠ 0).
▪️ Примеры таких условий
📍 Минимизация if:
создаст и сразу перейдёт, только если каталог успешно создан.
📍 Команда с fallback:
Если cp не удался - сработает echo.
📍 Успех или откат:
Если echo "Успешно" завершится с ошибкой (что редко, но возможно), то сработает и ||.
Чтобы избежать этого, оберните в скобки:
📍 Цепочка нескольких условий:
Проверяем наличие каталога
Если есть - заходим и выводим содержимое
Если нет - сообщение
📍 Проверка переменной:
▪️ Более сложные варианты использования
📍 Комбинирование условий:
📍 Логическая цепочка до первой ошибки:
📍 Псевдо-транзакции:
Если что-то пошло не так - rollback.
BashTex📱 #bash #utils
Когда вы пишете:
if command; then
echo "OK"
else
echo "Fail"
fi
В мире плачет один котенок…
command && echo "OK" || echo "Fail"
Это логические цепочки (&& и ||), которые позволяют писать коротко и эффективно.
Bash, как и многие языки, останавливает выполнение цепочки, если уже ясно, что дальше не нужно:
cmd1 && cmd2 - cmd2 выполняется только если cmd1 завершилась успешно (exit 0).
cmd1 || cmd2 - cmd2 выполняется только если cmd1 завершилась с ошибкой (exit ≠ 0).
mkdir newdir && cd newdir
создаст и сразу перейдёт, только если каталог успешно создан.
cp file.txt backup/ || echo "Не удалось скопировать!"
Если cp не удался - сработает echo.
make build && echo "Успешно" || echo "Ошибка"
Если echo "Успешно" завершится с ошибкой (что редко, но возможно), то сработает и ||.
Чтобы избежать этого, оберните в скобки:
make build && { echo "Успешно"; } || { echo "Ошибка"; }
[ -d logs ] && cd logs && ls || echo "Нет каталога logs"
Проверяем наличие каталога
Если есть - заходим и выводим содержимое
Если нет - сообщение
[[ -n $API_KEY ]] && echo "Ключ найден" || echo "Нет ключа"
[[ -f $file && -s $file ]] && echo "Файл существует и не пуст"
do_step1 && do_step2 && do_step3 || echo "Ошибка на одном из этапов"
backup && update && restart || rollback
Если что-то пошло не так - rollback.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
Please open Telegram to view this post
VIEW IN TELEGRAM
😁22👨💻1
Автоматическое масштабирование ресурсов контейнеров
Казалось бы, нетривиальная задача - нужно, чтобы контейнер автоматически подстраивался под нагрузку: добавлял CPU/memory, когда процесс задыхается, и освобождал ресурсы при простое. Все это без kubernetes, без swarm, просто bash + docker API. Попробуем реализовать.
🛠 Пример скрипта (называться пусть будет
BashTex📱 #bash
Казалось бы, нетривиальная задача - нужно, чтобы контейнер автоматически подстраивался под нагрузку: добавлял CPU/memory, когда процесс задыхается, и освобождал ресурсы при простое. Все это без kubernetes, без swarm, просто bash + docker API. Попробуем реализовать.
▪️ План скрипта:
Скрипт опрашиваетdocker stats --no-stream
Сравнивает текущую загрузку CPU/памяти с порогами
При превышении - обновляет лимиты контейнера черезdocker update
При простое - возвращает лимиты назад
Все это циклически, с логированием и защитой от дребезга (частых переключений)
auto-scale.sh)
#!/usr/bin/env bash
CONTAINER="webapp"
CPU_MAX=200000 # 200% CPU
CPU_MIN=50000 # 50% CPU
MEM_MAX="1g"
MEM_MIN="256m"
LOGFILE="/var/log/docker_autoscale.log"
INTERVAL=30
STABILITY=3 # сколько циклов подряд должна держаться нагрузка
cpu_high=0
cpu_low=0
log() { echo "$(date '+%F %T') $*" >> "$LOGFILE"; }
while true; do
read cpu mem <<<$(docker stats --no-stream --format "{{.CPUPerc}} {{.MemUsage}}" "$CONTAINER" \
| awk -F'[ %/]' '{printf "%d %d", $1, $2}')
if (( cpu > 80 )); then
((cpu_high++))
cpu_low=0
elif (( cpu < 30 )); then
((cpu_low++))
cpu_high=0
fi
if (( cpu_high >= STABILITY )); then
log "High load detected ($cpu%). Increasing limits..."
docker update --cpus="2.0" --memory="$MEM_MAX" "$CONTAINER" >/dev/null
cpu_high=0
elif (( cpu_low >= STABILITY )); then
log "Low load detected ($cpu%). Decreasing limits..."
docker update --cpus="0.5" --memory="$MEM_MIN" "$CONTAINER" >/dev/null
cpu_low=0
fi
sleep "$INTERVAL"
done
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Генерация таблиц прогресса
Реализация живой таблицы прогресса выполнения сприпта, обновляемой прямо в терминале - без внешних тулз, только
🛠 Скрипт:
▪️ Пояснения:
BashTex📱 #bash #utils
Реализация живой таблицы прогресса выполнения сприпта, обновляемой прямо в терминале - без внешних тулз, только
tput, trap. Звучит заманчиво.
#!/usr/bin/env bash
tasks=("Backup" "Sync configs" "Rebuild cache" "Restart services" "Cleanup")
total=${#tasks[@]}
done=0
# Убираем курсор
tput civis
# При выходе вернуть курсор
trap 'tput cnorm; echo' EXIT
# Заголовок таблицы
printf "%-20s | %-10s | %-10s\n" "Task" "Status" "Progress"
printf -- "---------------------------------------------\n"
# Печатаем пустые строки под таблицу
for ((i=0; i<total; i++)); do
printf "%-20s | %-10s | %-10s\n" "${tasks[i]}" "Pending" "0%"
done
# Запоминаем позицию курсора для обновлений
start_row=$(tput lines)
start_row=$((start_row - total))
# Функция обновления строки
update_row() {
local idx=$1
local status=$2
local progress=$3
tput cup $((start_row + idx)) 0
printf "%-20s | %-10s | %-10s\n" "${tasks[idx]}" "$status" "$progress"
}
# Основной цикл выполнения
for i in "${!tasks[@]}"; do
for p in {10..100..10}; do
update_row "$i" "Running" "${p}%"
sleep 0.1
done
update_row "$i" "Done" "100%"
done
tput cnorm
echo -e "\nВсе задачи завершены!"
tput civis / cnorm - скрывает и возвращает курсор.tput cup row col - перемещает курсор для перерисовки конкретной строки.trap '...' EXIT - гарантирует возврат нормального состояния терминала даже при Ctrl+C.printf с фиксированной шириной (%-20s) создает выровненную таблицу.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Please open Telegram to view this post
VIEW IN TELEGRAM
😁13🔥3🫡3
Создание песочницы для экспериментов
Иногда нужно проверить какую-то команду, поиграться с конфигами или собрать пакет - но без риска сломать систему. Для этого в linux можно сделать свою мини-песочницу, используя старое доброе
🛠 Скрипт создающий песочницу:
BashTex📱 #bash #utils
Иногда нужно проверить какую-то команду, поиграться с конфигами или собрать пакет - но без риска сломать систему. Для этого в linux можно сделать свою мини-песочницу, используя старое доброе
chroot и немного bash.chroot - это механизм, который меняет корень файловой системы для процесса. Все, что он видит, находится внутри изолированного каталога, и даже rm -rf / не затронет настоящую систему (если, конечно, настроено правильно🤓 ).
#!/usr/bin/env bash
SANDBOX="/opt/sandbox"
DEBIAN_MIRROR="https://deb.debian.org/debian"
ARCH=$(dpkg --print-architecture)
# Проверка зависимостей
for cmd in debootstrap chroot mount umount; do
command -v $cmd >/dev/null || { echo "$cmd not found"; exit 1; }
done
# Создание окружения, если нет
if [[ ! -d "$SANDBOX" ]]; then
echo "Создаю минимальную систему Debian..."
sudo debootstrap --arch="$ARCH" stable "$SANDBOX" "$DEBIAN_MIRROR"
fi
# Монтируем системные точки
sudo mount -t proc /proc "$SANDBOX/proc"
sudo mount --rbind /sys "$SANDBOX/sys"
sudo mount --rbind /dev "$SANDBOX/dev"
# Добавим базовые бинари для экспериментов
sudo cp /bin/bash "$SANDBOX/bin/"
sudo cp /usr/bin/ls "$SANDBOX/usr/bin/"
echo "Входим в песочницу!"
sudo chroot "$SANDBOX" /bin/bash
# После выхода - очистка
echo "Отмонтирую ресурсы..."
sudo umount -l "$SANDBOX/proc" "$SANDBOX/sys" "$SANDBOX/dev"
Здесь:debootstrapставит минимальный Debian прямо в каталог (/opt/sandbox)mountподключает системные псевдофайловые системы (/proc,/sys,/dev)chrootзапускает bash внутри нового корня
После выхода - все отмонтируется, и можно просто удалить/opt/sandbox
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Сравнение конфигураций между серверами
Иногда нужно понять, чем конфиги на dev и prod отличаются, но без полного копирования или внешних тулз.
🛠 Пример скрипта:
▪️ Как это работает
▪️ Расширение скрипта при необходимости:
1️⃣ Сравнение содержимого файлов:
2️⃣ Генерация markdown отчета:
3️⃣ Уведомление в телегу при изменениях:
BashTex📱 #bash
Иногда нужно понять, чем конфиги на dev и prod отличаются, но без полного копирования или внешних тулз.
Задача:
Сравнить/etc/nginx/и/etc/systemd/между двумя серверами, чтобы увидеть, какие файлы изменены, добавлены или удалены.
#!/usr/bin/env bash
REMOTE="[email protected]"
DIRS=("/etc/nginx" "/etc/systemd")
TMPDIR="/tmp/config-compare"
LOG="/tmp/config-diff.log"
mkdir -p "$TMPDIR"
> "$LOG"
for dir in "${DIRS[@]}"; do
echo "Checking $dir ..." | tee -a "$LOG"
rsync -avz --dry-run --delete "$REMOTE:$dir/" "$dir/" \
| grep -E '^deleting|^>f' \
| sed "s|^|$dir/ |" \
>> "$TMPDIR/rsync.diff"
done
if [[ -s "$TMPDIR/rsync.diff" ]]; then
echo -e "\nDifferences found:\n" | tee -a "$LOG"
cat "$TMPDIR/rsync.diff" | tee -a "$LOG"
else
echo "Configurations match across all directories." | tee -a "$LOG"
fi
rsync --dry-run --delete - имитирует синхронизацию, но ничего не меняет, выводит список различий между каталогами.grep -E '^>f|^deleting' - фильтрует только изменения (новые или удалённые файлы).
ssh "$REMOTE" "cat /etc/nginx/nginx.conf" > /tmp/remote.conf
diff -u /etc/nginx/nginx.conf /tmp/remote.conf || echo "nginx.conf differs!"
echo -e "## Config diff report\n\`\`\`\n$(cat $TMPDIR/rsync.diff)\n\`\`\`" > /tmp/diff_report.md
[[ -s $TMPDIR/rsync.diff ]] && curl -s -F "text=$(cat $TMPDIR/rsync.diff)" \
"https://api.telegram.org/bot$TOKEN/sendMessage?chat_id=$CHAT_ID"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
Системные уведомления через D-Bus и bash
Bash умеет не только писать логи в консоль - он может отправлять системные уведомления прямо в графическую среду, используя D-Bus. Это хороший способ сообщить пользователю о результатах скрипта, ошибках или завершении задач, не залезая в UI.
1️⃣ Простой способ - notify-send. Самая быстрая интеграция:
Работает через D-Bus (org.freedesktop.Notifications). Можно добавить приоритет, срок жизни, категории:
2️⃣ Напрямую через dbus-send. Если notify-send недоступен (например, в минимальной среде),
можно напрямую вызвать метод D-Bus:
Выглядит громоздко, но это чистый вызов через D-Bus, минуя внешние обертки. Можно внедрить в сценарии, где нужно абсолютное управление уведомлениями.
3️⃣ Уведомления в фоновом режиме. Если скрипт работает из cron или systemd-сервиса, нужно указать сеансовую шину D-Bus пользователя. Например, так:
Это позволяет отправлять уведомления от root в сессию конкретного пользователя.
4️⃣ Практический пример
Каждое выполнение скрипта будет сопровождаться визуальными уведомлениями в системе.
▪️ Динамические уведомления. Можно обновлять уведомление (пример для GNOME/KDE, не все среды поддерживают):
BashTex📱 #bash #utils
Bash умеет не только писать логи в консоль - он может отправлять системные уведомления прямо в графическую среду, используя D-Bus. Это хороший способ сообщить пользователю о результатах скрипта, ошибках или завершении задач, не залезая в UI.
notify-send "Бэкап завершен" "Все файлы успешно сохранены" --icon=dialog-information
Работает через D-Bus (org.freedesktop.Notifications). Можно добавить приоритет, срок жизни, категории:
notify-send \
--urgency=critical \
--expire-time=10000 \
--app-name="BackupScript" \
"Ошибка резервного копирования" \
"Недостаточно места на диске!"
можно напрямую вызвать метод D-Bus:
dbus-send --session --type=method_call \
--dest=org.freedesktop.Notifications \
/org/freedesktop/Notifications \
org.freedesktop.Notifications.Notify \
string:"BashScript" \
uint32:0 \
string:"dialog-warning" \
string:"Системное уведомление" \
string:"Задача завершена с ошибками" \
array:string:"ОК" \
dict:string:string: \
int32:-1
Выглядит громоздко, но это чистый вызов через D-Bus, минуя внешние обертки. Можно внедрить в сценарии, где нужно абсолютное управление уведомлениями.
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
notify-send "Backup completed" "Проверено $(date)"
Это позволяет отправлять уведомления от root в сессию конкретного пользователя.
#!/usr/bin/env bash
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
TASK="Резервное копирование /home"
notify-send "Начато" "$TASK..."
if tar czf /backup/home_$(date +%F).tar.gz /home 2>/dev/null; then
notify-send "Успешно" "$TASK завершено"
else
notify-send "Ошибка" "$TASK не выполнено"
fi
Каждое выполнение скрипта будет сопровождаться визуальными уведомлениями в системе.
ID=$(notify-send "Выполняется резервное копирование..." --print-id)
sleep 5
notify-send "Завершено" "Файлы успешно сохранены" --replace-id="$ID"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2🤨1
Вставка последнего аргумента без копипасты
Сколько раз вы выполняли команду, вроде:
а потом через секунду нужно:
и снова набираете руками путь или выделяете путь?
Есть способ не повторять последнее слово - bash это помнит.
⠀
1️⃣ Alt + . - вставка последнего аргумента
В любой момент нажмите
превратится в
Нажимайте Alt + . несколько раз, чтобы пройтись по аргументам из истории (Bash перебирает их назад).
2️⃣ Альтернатива: !$ и !. Тоже самое, но в виде подстановки из истории:
или
3️⃣ Примеры
Быстрое удаление того, что только что создали:
Скопировали и сразу зашли:
Переместили файл и открыли его в редакторе:
Копируете в несколько мест подряд:
BashTex📱 #bash #utils
Сколько раз вы выполняли команду, вроде:
cp file.txt /tmp/somedir/
а потом через секунду нужно:
cd /tmp/somedir/
и снова набираете руками путь или выделяете путь?
Есть способ не повторять последнее слово - bash это помнит.
⠀
В любой момент нажмите
Alt + . - и bash подставит последний аргумент предыдущей команды.
cp file.txt /tmp/somedir/
cd <Alt+.>
превратится в
cd /tmp/somedir/
Нажимайте Alt + . несколько раз, чтобы пройтись по аргументам из истории (Bash перебирает их назад).
cd !$
или
cd !.
!$ - последний аргумент предыдущей команды.!. - то же самое, но безопаснее (некоторые шеллы по-разному интерпретируют $).Быстрое удаление того, что только что создали:
mkdir new_dir
rm -r !$
Скопировали и сразу зашли:
cp -r project /opt/
cd !$
Переместили файл и открыли его в редакторе:
mv data.log /var/log/archive/
nano !$
Копируете в несколько мест подряд:
cp backup.tar.gz /mnt/usb/
cp !$ /srv/backups/
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥1😁1