Параллельная обработка файлов без GNU Parallel
▪️ Базовый пример: запуск в фоне
Все файлы сжимаются одновременно - но это нагружает CPU. Хотелось бы ограничить количество потоков, для этого добавим контроль.
▪️ Контроль количества одновременно работающих задач
Классика для bash 4+:
▪️ Ещё лаконичнее через xargs
🌟 Работает даже в старых системах (без wait -n).
▪️ Чуть сложнее: обработка с логированием и статусом
Вывод:
Все просто, читаемо и работает без внешних зависимостей.
BashTex📱 #bash #utils
for f in *.log; do
gzip "$f" &
done
wait
Все файлы сжимаются одновременно - но это нагружает CPU. Хотелось бы ограничить количество потоков, для этого добавим контроль.
Классика для bash 4+:
MAXJOBS=4
for f in *.log; do
gzip "$f" &
(( $(jobs -r | wc -l) >= MAXJOBS )) && wait -n
done
wait
jobs -r- считает активные фоновые процессыwait -n- дожидается завершения одного из них
В итоге максимум 4 задачи одновременно
ls *.log | xargs -n1 -P4 bash -c 'gzip "$0"'
-n1 - по одному аргументу на процесс
-P4 - максимум 4 параллельных процесса
bash -c 'gzip "$0"' - шаблон выполнения
process_file() {
local f="$1"
echo "[START] $f"
sleep $((RANDOM % 5)) # эмуляция нагрузки
echo "[DONE] $f"
}
export -f process_file
ls *.log | xargs -n1 -P3 bash -c 'process_file "$0"'
Вывод:
[START] file1.log
[START] file2.log
[START] file3.log
[DONE] file2.log
[DONE] file1.log
[START] file4.log
[DONE] file3.log
[DONE] file4.log
Все просто, читаемо и работает без внешних зависимостей.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Изоляция временных директорий для скриптов
Каждый серьезный скрипт должен оставлять систему чистой после работы. Для этого нужно уметь создавать, использовать и безопасно очищать временные директории, особенно если в них хранятся промежуточные файлы, ключи или результаты сборки.
Многие пишут так:
Это рискованно, потому что:
- Возможна гонка при
- Если скрипт завершится с ошибкой -
- Несколько процессов перетрут файлы друг друга
▪️ Решение: mktemp + trap
▪️ Пример: временное рабочее окружение
При любом исходе (Ctrl+C, ошибка, SIGTERM) директория будет удалена автоматически.
▪️ Уровень выше: временные файлы внутри каталога
Все временные артефакты изолированы в одной папке. После завершения скрипта следов нет.
▪️ Безопасность и права
По умолчанию
Можно задать вручную:
Полезно, если скрипт работает под рутом и обрабатывает конфиденциальные данные.
BashTex📱 #bash #utils
Каждый серьезный скрипт должен оставлять систему чистой после работы. Для этого нужно уметь создавать, использовать и безопасно очищать временные директории, особенно если в них хранятся промежуточные файлы, ключи или результаты сборки.
Многие пишут так:
TMPDIR="/tmp/mynoscript"
mkdir -p "$TMPDIR"
# ...
rm -rf "$TMPDIR"
Это рискованно, потому что:
- Возможна гонка при
mkdir в /tmp- Если скрипт завершится с ошибкой -
rm -rf не выполнится- Несколько процессов перетрут файлы друг друга
TMPDIR=$(mktemp -d -t mynoscript.XXXXXX)
trap 'rm -rf "$TMPDIR"' EXIT
mktemp -d- создает уникальную директориюtrap ... EXIT- гарантирует удаление даже при ошибках
Безопасно, изолированно и без коллизий
#!/usr/bin/env bash
set -euo pipefail
TMPDIR=$(mktemp -d -t build.XXXXXX)
trap 'echo "Cleaning $TMPDIR"; rm -rf "$TMPDIR"' EXIT
echo "Workdir: $TMPDIR"
cp -r src/* "$TMPDIR/"
pushd "$TMPDIR" >/dev/null
make all
popd >/dev/null
При любом исходе (Ctrl+C, ошибка, SIGTERM) директория будет удалена автоматически.
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
LOG="$TMPDIR/run.log"
OUT="$TMPDIR/result.txt"
echo "Starting..." > "$LOG"
echo "42" > "$OUT"
Все временные артефакты изолированы в одной папке. После завершения скрипта следов нет.
По умолчанию
mktemp создает директорию с правами 700.Можно задать вручную:
TMPDIR=$(mktemp -d -p /var/tmp mynoscript.XXXXXX)
chmod 700 "$TMPDIR"
Полезно, если скрипт работает под рутом и обрабатывает конфиденциальные данные.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Динамическое создание и использование временных файлов
Иногда хочется или нужно передавать данные между процессами без создания реальных временных файлов: быстро, безопасно и с контролем потока. Вот тут в дело вступают именованные каналы (named pipes, FIFO).
▪️ Пример 1: Обработка данных на лету
Здесь mkfifo создает канал, а один процесс пишет в него, пока другой читает.
Результат - никаких temp-файлов, только живой поток.
▪️ Пример 2: Конвейер с фильтрацией и tee
Это хороший способ подменить лог-файл, не записывая на диск до тех пор, пока не нужно.
▪️ Пример 3: Генерация данных и параллельная обработка
Здесь один процесс производит список файлов, а другой параллельно обрабатывает их.
Нет конфликтов записи, нет tmp-файлов, нет гонок.
🌟 Подводные камни
FIFO блокируется, если один конец не открыт: пока нет читателя, писатель висит.
При множественных писателях стоит использовать lock-механизмы (flock или temp lock-файл).
Не забывай очищать rm "$fifo", иначе в
📌 Когда это реально нужно
При распараллеливании bash-пайплайнов без промежуточных файлов;
Для асинхронных логгеров: один пишет, другой агрегирует;
Для фоново работающих демонов, взаимодействующих через потоки.
BashTex📱 #bash #utils
Иногда хочется или нужно передавать данные между процессами без создания реальных временных файлов: быстро, безопасно и с контролем потока. Вот тут в дело вступают именованные каналы (named pipes, FIFO).
Что это такое
mkfifo создает специальный файл, через который можно организовать двусторонний обмен данными между процессами, без хранения на диске. Потоки читаются и пишутся вживую, а данные не буферизуются, пока другой процесс не откроет противоположную сторону.
#!/usr/bin/env bash
pipe=$(mktemp -u) # создаем уникальное имя
mkfifo "$pipe"
# Пишем данные в FIFO в фоне
{
for i in {1..5}; do
echo "[$(date +%T)] Обработка задачи #$i"
sleep 1
done > "$pipe"
} &
# Читаем и форматируем поток
while read -r line; do
echo ">>> $line"
done < "$pipe"
rm "$pipe"
Здесь mkfifo создает канал, а один процесс пишет в него, пока другой читает.
Результат - никаких temp-файлов, только живой поток.
#!/usr/bin/env bash
fifo=$(mktemp -u)
mkfifo "$fifo"
# Пишем лог в FIFO
{
dmesg | grep "error" > "$fifo"
} &
# Читаем и одновременно сохраняем
tee /tmp/errors.log < "$fifo" | awk '{print toupper($0)}'
rm "$fifo"
Это хороший способ подменить лог-файл, не записывая на диск до тех пор, пока не нужно.
#!/usr/bin/env bash
fifo=$(mktemp -u)
mkfifo "$fifo"
producer() {
for f in *.log; do
echo "$f"
done > "$fifo"
}
consumer() {
while read -r file; do
grep "ERROR" "$file" >> errors_all.txt
done < "$fifo"
}
producer & consumer
wait
rm "$fifo"
Здесь один процесс производит список файлов, а другой параллельно обрабатывает их.
Нет конфликтов записи, нет tmp-файлов, нет гонок.
FIFO блокируется, если один конец не открыт: пока нет читателя, писатель висит.
При множественных писателях стоит использовать lock-механизмы (flock или temp lock-файл).
Не забывай очищать rm "$fifo", иначе в
/tmp может накапливаться мусор.При распараллеливании bash-пайплайнов без промежуточных файлов;
Для асинхронных логгеров: один пишет, другой агрегирует;
Для фоново работающих демонов, взаимодействующих через потоки.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Please open Telegram to view this post
VIEW IN TELEGRAM
😁11👨💻1
Собственная корзина
С помощью bash можно написать собственную корзину и при вводе
▪️ Реализация: базовый пример
Перезапусти терминал и теперь каждый
▪️ Пример использования
А теперь:
Никаких потерь. Можно легко вернуть:
▪️ Расширение: лог и автоочистка. Добавим журнал и автоматическую очистку старых файлов:
Теперь:
Все удаления пишутся в
Старые файлы очищаются автоматически
BashTex📱 #bash #utils
С помощью bash можно написать собственную корзину и при вводе
rm будет не удаление, а перемещение файла + все это будет с датой и логом. + Немного допилив можно сделать корзину в автоочисткой через 30 дней. Будет полезно тем, кто часто удаляет нужное.Идея
Перехватываем вызов rm через алиас или функцию и вместо удаления отправляем файлы в~/.quarantine/YYYY-MM-DD/, чтобы потом можно было восстановить.
# ~/.bashrc или отдельный файл ~/.bash_safe_rm.sh
SAFE_RM_DIR="$HOME/.quarantine"
safe_rm() {
local date_dir="$SAFE_RM_DIR/$(date +%F)"
mkdir -p "$date_dir"
for file in "$@"; do
if [[ -e "$file" ]]; then
local dest="$date_dir/$(basename "$file")_$(date +%H%M%S)"
mv "$file" "$dest"
echo "Moved '$file' -> '$dest'"
else
echo "File not found: $file"
fi
done
}
alias rm='safe_rm'
Перезапусти терминал и теперь каждый
rm file.txt будет просто перемещать файл.
$ echo "test" > /tmp/test.txt
$ rm /tmp/test.txt
Moved '/tmp/test.txt' -> '/home/user/.quarantine/2025-12-02/test.txt_102355'
А теперь:
$ ls ~/.quarantine/2025-12-02/
test.txt_102355
Никаких потерь. Можно легко вернуть:
mv ~/.quarantine/2025-12-02/test.txt_102355 ~/Documents/test.txt
safe_rm() {
local date_dir="$SAFE_RM_DIR/$(date +%F)"
mkdir -p "$date_dir"
local log_file="$SAFE_RM_DIR/deleted.log"
for file in "$@"; do
if [[ -e "$file" ]]; then
local dest="$date_dir/$(basename "$file")_$(date +%H%M%S)"
mv "$file" "$dest"
echo "$(date '+%F %T') | $PWD/$file -> $dest" >> "$log_file"
echo "$file quarantined"
else
echo "File not found: $file"
fi
done
# автоочистка старше 30 дней
find "$SAFE_RM_DIR" -type d -mtime +30 -exec rm -rf {} + 2>/dev/null
}
Теперь:
Все удаления пишутся в
~/.quarantine/deleted.logСтарые файлы очищаются автоматически
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2
Реализация кэша команд
Некоторые команды тратят секунды или даже минуты, например,
Будем сохранять:
результат выполнения команды
время последнего обновления
время жизни кэша (TTL)
И в следующий раз bash просто берет результат из файла, если он не устарел, при этом экономя CPU.
🛠 Пример реализации
▪️ Пример использования
При первом вызове:
А при повторном (в течение 60 сек):
▪️ Очистка старых кэшей
Можно добавить в cron:
Или в саму функцию:
BashTex📱 #bash #utils
Некоторые команды тратят секунды или даже минуты, например,
curl, find, du, git log. Если их результат не меняется часто, зачем выполнять их заново? Можно сделать кэш прямо в bash, без redis и внешних библиотекБудем сохранять:
результат выполнения команды
время последнего обновления
время жизни кэша (TTL)
И в следующий раз bash просто берет результат из файла, если он не устарел, при этом экономя CPU.
# ~/.bash_cache.sh
CACHE_DIR="$HOME/.bash_cache"
mkdir -p "$CACHE_DIR"
# $1 — время жизни (сек), $2 — команда
cache_run() {
local ttl="$1"
shift
local cmd="$*"
local key
key=$(echo "$cmd" | md5sum | awk '{print $1}')
local cache_file="$CACHE_DIR/$key.cache"
local ts_file="$CACHE_DIR/$key.ts"
# если кэш свежий — читаем
if [[ -f "$cache_file" && -f "$ts_file" ]]; then
local ts=$(<"$ts_file")
local now=$(date +%s)
if (( now - ts < ttl )); then
echo "[cache hit] $cmd"
cat "$cache_file"
return 0
fi
fi
# иначе выполняем и обновляем
echo "[cache miss] $cmd"
eval "$cmd" | tee "$cache_file"
date +%s > "$ts_file"
}
# Кэшируем команду на 60 секунд
cache_run 60 "curl -s https://api.github.com/repos/linux/kernel"
При первом вызове:
[cache miss] curl -s https://api.github.com/repos/linux/kernel
{ "id": 2325298, "name": "linux", ... }
А при повторном (в течение 60 сек):
[cache hit] curl -s https://api.github.com/repos/linux/kernel
{ "id": 2325298, "name": "linux", ... }
Можно добавить в cron:
find "$HOME/.bash_cache" -type f -mtime +1 -delete
Или в саму функцию:
(( RANDOM % 10 == 0 )) && find "$CACHE_DIR" -type f -mtime +1 -delete &
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Загрузка файлов по HTTP через /dev/tcp
Когда на сервере нет
Эта конструкция открывает сетевое соединение прямо из bash, без внешних утилит. Дальше можно писать и читать данные из этого дескриптора как из обычного файла.
▪️ Минимальный пример HTTP-запроса
скрипт откроет TCP-сокет на 80 порту,
отправит минимальный HTTP-запрос,
выведет сырые заголовки и контент ответа.
▪️ Скачивание файла с фильтрацией заголовков
Обычно хочется получить только тело, без HTTP-заголовков. Для этого можно пропустить пустую строку (\r) - границу заголовков:
▪️ HTTPS?
/dev/tcp умеет только чистый TCP, без TLS. Но можно обойтись через openssl s_client:
Да, это немного костыль, но работает даже на минимальных системах без wget/curl.
BashTex📱 #bash #utils
Когда на сервере нет
curl, wget и даже nc, а скачать файл все равно нужно, то тут на помощь приходит встроенный TCP-интерфейс: /dev/tcp/host/port. Bash поддерживает встроенные TCP/UDP-сокеты:exec {fd}>/dev/tcp/bashtex.com/80
Эта конструкция открывает сетевое соединение прямо из bash, без внешних утилит. Дальше можно писать и читать данные из этого дескриптора как из обычного файла.
#!/usr/bin/env bash
HOST="bashtex.com"
PATH="/index.html"
exec 3<>/dev/tcp/$HOST/80
# Отправляем HTTP-запрос
printf "GET $PATH HTTP/1.1\r\nHost: $HOST\r\nConnection: close\r\n\r\n" >&3
# Читаем ответ
while IFS= read -r line <&3; do
echo "$line"
done
exec 3>&-
скрипт откроет TCP-сокет на 80 порту,
отправит минимальный HTTP-запрос,
выведет сырые заголовки и контент ответа.
Обычно хочется получить только тело, без HTTP-заголовков. Для этого можно пропустить пустую строку (\r) - границу заголовков:
#!/usr/bin/env bash
HOST="bashtex.com"
FILE="/file.txt"
OUT="file.txt"
exec 3<>/dev/tcp/$HOST/80
printf "GET $FILE HTTP/1.1\r\nHost: $HOST\r\nConnection: close\r\n\r\n" >&3
# Пропускаем заголовки
while IFS= read -r line <&3; do
[[ $line == $'\r' ]] && break
done
# Сохраняем тело
cat <&3 > "$OUT"
exec 3>&-
echo "Файл сохранён: $OUT"
/dev/tcp умеет только чистый TCP, без TLS. Но можно обойтись через openssl s_client:
exec 3<> >(openssl s_client -connect bashtex.com:443 -quiet)
printf "GET / HTTP/1.1\r\nHost: bashtex.com\r\nConnection: close\r\n\r\n" >&3
cat <&3
Да, это немного костыль, но работает даже на минимальных системах без wget/curl.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3🗿1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁16👍5
Централизованный сбор логов со всех серверов по SSH
Когда в инфраструктуре 3 и более серверов, необходимость собирать логи в одно место становится актуальной. Не всем необходимо разворачивать полноценный ELK/Graylog. Может быть достаточно скрипта, который собирает логи по SSH и приводит их к единому формату.
Сегодня покажу, как сделать легкую систему централизованного логирования на
Допустим:
Каждый наш сервер умеет отдавать свои логи через:
Мы создаем на главном сервере каталог:
И напрягаем bash забирать туда свежие логи по расписанию.
Что будем собирать:
1) systemd-журналы:
2) классические логи:
🛠 Скрипт централизованного сбора логов
-a - сохраняет структуру, права
-z - сжатие
--delete - удаляет локальные файлы, которых уже нет на сервере (чтобы каталог не рос бесконечно)
Структура в итоге выглядит так:
▪️ Версия с датой. Добавим архивирование и метку времени:
Можно затем сделать cron-задачу:
BashTex📱 #bash
Когда в инфраструктуре 3 и более серверов, необходимость собирать логи в одно место становится актуальной. Не всем необходимо разворачивать полноценный ELK/Graylog. Может быть достаточно скрипта, который собирает логи по SSH и приводит их к единому формату.
Сегодня покажу, как сделать легкую систему централизованного логирования на
rsync + journalctl, без агентов, демонов и тяжелых сервисов.Допустим:
Каждый наш сервер умеет отдавать свои логи через:
journalctl --since --until - системные логи/var/log/ - классические текстовые логиМы создаем на главном сервере каталог:
/var/log/central/
├── server1/
├── server2/
├── server3/
└── ...
И напрягаем bash забирать туда свежие логи по расписанию.
Что будем собирать:
1) systemd-журналы:
journalctl --since "1 hour ago" --output=short-iso
2) классические логи:
/var/log/*.log
/var/log/nginx/
/var/log/syslog*
/var/log/auth.log*
#!/usr/bin/env bash
set -euo pipefail
# Список серверов
SERVERS=("srv1" "srv2" "srv3")
USER="logcollector"
DEST="/var/log/central"
SINCE="1 hour ago"
mkdir -p "$DEST"
for host in "${SERVERS[@]}"; do
echo "[+] Сбор логов с $host"
HOST_DIR="$DEST/$host"
mkdir -p "$HOST_DIR"
# 1) journalctl → локальный файл
ssh "$USER@$host" \
"journalctl --since \"$SINCE\" --output=short-iso" \
> "$HOST_DIR/journal.log"
# 2) rsync логов
rsync -az --delete \
"$USER@$host:/var/log/" \
"$HOST_DIR/textlogs/"
done
ssh "journalctl …" - Мы вызываем journalctl прямо на удаленной машине и как итог лог формируется быстро и передается по SSH. Формат short-iso нужен, чтобы было удобно анализировать.rsync -az --delete-a - сохраняет структуру, права
-z - сжатие
--delete - удаляет локальные файлы, которых уже нет на сервере (чтобы каталог не рос бесконечно)
Структура в итоге выглядит так:
/var/log/central/srv1/
├── journal.log
└── textlogs/
├── syslog
├── auth.log
├── nginx/access.log
└── ...
TS=$(date +%F_%H-%M)
ssh "$USER@$host" \
"journalctl --since \"$SINCE\" --output=short-iso" \
> "$HOST_DIR/journal_$TS.log"
rsync -az "$USER@$host:/var/log/" "$HOST_DIR/textlogs_$TS/"
Можно затем сделать cron-задачу:
0 * * * * /usr/local/bin/collect-logs.sh
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Используй предстоящие новогодние выходные наилучшим образом! Изучай новые технологии или закрой пробелы в знаниях по своему стеку.
Стань экспертом в следующих направлениях:
• Системное администрирование
• Информационная безопасность
• Сетевое администрирование
• Этичный хакинг
Ссылка для своих: https://news.1rj.ru/str/admbooks
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Локальные снапшоты каталога
Одна из интересных и полезных идей для реализации: сделать машину времени для каталога т.е. реализовать сценарий при котором возможно вернуться к состоянию вчера/час назад/неделю назад (без btrfs, zfs или lvm)
Решение: rsync + hardlinks
Это ближе всех к btrfs/ZFS-снапшотам в мире обычных файловых систем (ext4/xfs).
▪️ Структура:
Каждый каталог - полноценная копия состояния.
🛠 Мини-скрипт
▪️ Восстановление состояния каталога. Чтобы вернуть старую версию:
Либо наоборот: перейти в каталог снапшота и увидеть все как было.
▪️ Автоматизация. Например, снимок каждый час:
▪️ Полезные дополнения
1️⃣ Автопургатор (ретеншн-политика)
Удалить снапшоты старше 30 дней.
2️⃣ Игнорирование временных файлов. Создай
И вызывай rsync так:
BashTex📱 #bash #utils
Одна из интересных и полезных идей для реализации: сделать машину времени для каталога т.е. реализовать сценарий при котором возможно вернуться к состоянию вчера/час назад/неделю назад (без btrfs, zfs или lvm)
Решение: rsync + hardlinks
Это ближе всех к btrfs/ZFS-снапшотам в мире обычных файловых систем (ext4/xfs).
/backups/
2025-12-05-12:00/
2025-12-05-13:00/
2025-12-05-14:00/
Каждый каталог - полноценная копия состояния.
#!/usr/bin/env bash
set -e
SRC="/home/user/project"
DST="/backups"
TS=$(date +"%Y-%m-%d-%H:%M")
LAST="$DST/latest"
NEW="$DST/$TS"
mkdir -p "$DST"
if [[ -d "$LAST" ]]; then
echo "[i] Using hardlinks from: $LAST"
rsync -a --delete --link-dest="$LAST" "$SRC/" "$NEW/"
else
echo "[i] First snapshot — no link-dest"
rsync -a --delete "$SRC/" "$NEW/"
fi
# Update the "latest" symlink
rm -f "$LAST"
ln -s "$(basename "$NEW")" "$LAST"
echo "[i] Snapshot created: $NEW"
rsync -a —link-dest=... - команда говорит сравни каталог с предыдущим снапшотом и все неизмененные файлы сделай через hardlink. Это не копия, а именно вторая ссылка на тот же inode. Место: +0 байт.--delete - удаленные файлы тоже исчезнут из новой точки — snapshot становится точным состоянием дерева в данный момент.Symlink latest - позволяет быстро создавать следующую точку, не перебирая каталоги.
rsync -a /backups/2025-12-05-12:00/ /home/user/project/
Либо наоборот: перейти в каталог снапшота и увидеть все как было.
0 * * * * /usr/local/bin/snapshot.sh
find /backups -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
Удалить снапшоты старше 30 дней.
.rsync-filter:
- *.tmp
- .cache/
И вызывай rsync так:
rsync -a --filter='. .rsync-filter' ...
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Привет. Вот тебе самые топовые каналы по IT!
⚙️ Free Znanija (IT) — Самая огромная коллекция платных курсов, которые можно скачать бесплатно;
👩💻 IT Books — Самая огромная библиотека книг;
💻 Hacking & InfoSec Base — Крутой блог белого хакера;
🛡 CyberGuard — Всё про ИБ;
🤔 ИБ Вакансии — Всё, чтобы найти работу в ИБ;
👩💻 linux administration — Всё про Линукс;
👩💻 Программистика — Python, python и ещё раз python;
👩💻 GameDev Base — Всё про GameDev;
😆 //code — Самые топовые мемы по IT:
Подпишись, чтобы не потерять!
Подпишись, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
Генерация unit файлов из шаблонов
Если у вас десятки сервисов, работающих по схожей схеме (например, несколько python или node-приложений), руками плодить unit-файлы в
▪️ Простейший шаблон. Создаем
▪️ Генерация через bash
▪️ Массовая генерация из списка. Храним параметры сервисов в CSV:
А bash все развернет:
BashTex📱 #bash #utils
Если у вас десятки сервисов, работающих по схожей схеме (например, несколько python или node-приложений), руками плодить unit-файлы в
/etc/systemd/system - сомнительное удовольствие. Правильнее и логичнее будет автоматизировать путем генерирации юнитов из шаблонов через bash.service.tpl:
[Unit]
Denoscription={{NAME}} service
After=network.target
[Service]
Type=simple
User={{USER}}
WorkingDirectory={{WORKDIR}}
ExecStart={{EXEC}}
Restart=always
[Install]
WantedBy=multi-user.target
#!/bin/bash
set -euo pipefail
TEMPLATE="./service.tpl"
OUTPUT_DIR="/etc/systemd/system"
generate_unit() {
local name="$1" user="$2" workdir="$3" exec="$4"
local outfile="$OUTPUT_DIR/${name}.service"
sed \
-e "s|{{NAME}}|$name|g" \
-e "s|{{USER}}|$user|g" \
-e "s|{{WORKDIR}}|$workdir|g" \
-e "s|{{EXEC}}|$exec|g" \
"$TEMPLATE" > "$outfile"
echo "Сервис $name создан: $outfile"
}
# Пример использования
generate_unit "myapp" "deploy" "/opt/myapp" "/opt/myapp/venv/bin/python app.py"
systemctl daemon-reload
systemctl enable myapp --now
name,user,workdir,exec
app1,deploy,/opt/app1,/opt/app1/start.sh
app2,deploy,/opt/app2,/usr/bin/python3 /opt/app2/run.py
А bash все развернет:
#!/bin/bash
while IFS=, read -r name user workdir exec; do
[[ "$name" == "name" ]] && continue # пропускаем заголовок
generate_unit "$name" "$user" "$workdir" "$exec"
done < services.csv
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3