Добавить в корзинуПозвонить
Найти в Дзене

Скрипт, который не ломается на втором запуске

Бывало такое: запускаете скрипт настройки сервера, а он орёт «пакет уже установлен» и падает? Или молча дублирует конфиги, а потом всё едет? Идемпотентность - это когда повторяете одно и то же действие много раз, а результат не меняется. Как выключатель: щёлкайте сколько угодно - свет либо включится, либо выключится. Без дыма и искр. ➤ Три функции, которые спасут ваши нервы Кладёте в начало любого скрипта - и спите спокойно: #!/bin/bash set -euo pipefail # Ставим пакет, только если его нет ensure_pkg() { dpkg -s "$1" &>/dev/null && { echo "$1 уже стоит"; return 0; } echo "Ставим $1..." apt-get install -y "$1" } # Добавляем строку в файл, только если её там нет ensure_line() { grep -qxF "$1" "$2" 2>/dev/null && { echo "Строка уже есть в $2"; return 0; } echo "$1" | tee -a "$2" } # Запускаем сервис, только если он не крутится ensure_svc() { systemctl is-active --quiet "$1" && { echo "$1 уже работает"; return 0; } systemctl start "$1" && systemctl enable "$1" } Логика простая: с

Скрипт, который не ломается на втором запуске

Бывало такое: запускаете скрипт настройки сервера, а он орёт «пакет уже установлен» и падает? Или молча дублирует конфиги, а потом всё едет?

Идемпотентность - это когда повторяете одно и то же действие много раз, а результат не меняется. Как выключатель: щёлкайте сколько угодно - свет либо включится, либо выключится. Без дыма и искр.

➤ Три функции, которые спасут ваши нервы

Кладёте в начало любого скрипта - и спите спокойно:

#!/bin/bash

set -euo pipefail

# Ставим пакет, только если его нет

ensure_pkg() {

dpkg -s "$1" &>/dev/null && { echo "$1 уже стоит"; return 0; }

echo "Ставим $1..."

apt-get install -y "$1"

}

# Добавляем строку в файл, только если её там нет

ensure_line() {

grep -qxF "$1" "$2" 2>/dev/null && { echo "Строка уже есть в $2"; return 0; }

echo "$1" | tee -a "$2"

}

# Запускаем сервис, только если он не крутится

ensure_svc() {

systemctl is-active --quiet "$1" && { echo "$1 уже работает"; return 0; }

systemctl start "$1" && systemctl enable "$1"

}

Логика простая: сначала проверяем, потом делаем.

➤ Как это выглядит в деле

Вместо простыни из if-else пишете читаемый список желаемого:

echo "Пора наверное навести порядок..."

ensure_pkg "nginx"

ensure_pkg "jq"

ensure_pkg "htop"

ensure_line "vm.swappiness=10" /etc/sysctl.conf

sysctl -p &>/dev/null

ensure_svc "nginx"

echo "Закончили. Хоть десять раз запустите - ни одной ошибки не увидите :D."

По сути, мы только что написали декларативную спецификацию: говорим «что должно быть», а не «как сделать». Это ровно то, за что все любят Ansible и Terraform, только на голом bash.

➤ Где ещё пригодится этот приём

- SQL-миграции: CREATE TABLE IF NOT EXISTS вместо просто CREATE

- Работа с API: метод PUT идемпотентен, POST - нет

- CI/CD: повторный запуск пайплайна не должен создавать дубликаты артефактов

- Форма заказа на сайте: защита от двойного нажатия через идемпотентный ключ

👉🏻 Я в Telegram - https://dzen.ru/id/686102a27e39653c3429f77f

👉🏻 Я в VK - vk.com/helcode

👉🏻 Я на Boosty - boosty.to/helcode