Бинарные флаги и побитовые операции
Bash - не только про строки. В нtм легко использовать побитовую арифметику (&, |, ^, ~, <<, >>) для управления флагами, что бывает полезно в админских скриптах.
▪️ Базовая логика. Каждый бит числа можно трактовать как флаг (0 - выключено, 1 - включено):
▪️ Установка флага (OR |)
▪️ Проверка флага (AND &)
▪️ Сброс флага (AND + NOT &~)
▪️ Инверсия (XOR ^)
▪️ Практические кейсы
1️⃣ Система разрешений в скриптах. Можно задавать доступ к операциям через биты вместо кучи if:
2️⃣ Упаковка нескольких состояний в одно число. Например, код статуса сервиса:
3️⃣ Быстрые флаги для CLI-опций
4️⃣ Флаги как компактная замена массивов. Вместо массива enabled_features=(...) можно хранить все в одной переменной. Это особенно ценно при передаче значений между процессами.
BashTex📱 #bash #utils
Bash - не только про строки. В нtм легко использовать побитовую арифметику (&, |, ^, ~, <<, >>) для управления флагами, что бывает полезно в админских скриптах.
FLAG_READ=1 # 0001
FLAG_WRITE=2 # 0010
FLAG_EXEC=4 # 0100
FLAG_DELETE=8 # 1000
rights=0
rights=$(( rights | FLAG_READ | FLAG_WRITE ))
echo $rights # 3 (0001 + 0010 = 0011)
if (( rights & FLAG_WRITE )); then
echo "Есть право записи"
fi
rights=$(( rights & ~FLAG_READ ))
echo $rights # теперь без read
rights=$(( rights ^ FLAG_EXEC )) # переключение: если был - уберется, если не был - включится
if (( user_flags & FLAG_DELETE )); then
rm "$file"
fi
STATUS_RUNNING=1
STATUS_RESTARTING=2
STATUS_FAILED=4
status=$(( STATUS_RUNNING | STATUS_RESTARTING ))
(( status & STATUS_FAILED )) && echo "Ошибка!"
OPT_VERBOSE=1
OPT_DRYRUN=2
OPT_FORCE=4
opts=0
[[ $1 == "-v" ]] && opts=$(( opts | OPT_VERBOSE ))
[[ $1 == "-f" ]] && opts=$(( opts | OPT_FORCE ))
(( opts & OPT_VERBOSE )) && echo "[VERBOSE MODE]"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Создание оффлайн инсталлятора из .deb зависимостей
Иногда сервер или рабочая машина не имеет прямого доступа в интернет. Но поставить нужный софт все же нужно. Решение: собрать локальный оффлайн инсталлятор из уже установленных пакетов и их зависимостей.
▪️ Установка dpkg-repack. На машине с интернетом:
▪️ Репак пакета в .deb. Если пакет уже стоит в системе:
▪️ Репак с зависимостями. Чтобы вытащить пакет + его зависимости:
▪️ Итог - "папка-инсталлятор". В каталоге будут все нужные .deb:
▪️ Установка на оффлайн серваке. Переносим папку, потом:
Можно превратить папку в локальный APT-репозиторий:
и подключить его через sources.list.
BashTex📱 #bash #utils
Иногда сервер или рабочая машина не имеет прямого доступа в интернет. Но поставить нужный софт все же нужно. Решение: собрать локальный оффлайн инсталлятор из уже установленных пакетов и их зависимостей.
sudo apt install dpkg-repack
dpkg-repack htop
# создаст htop_3.0.5-1_amd64.deb
mkdir offline-installer && cd offline-installer
# пример для nginx
for pkg in $(apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
nginx | grep "^\w"); do
dpkg-repack "$pkg"
done
ls *.deb
nginx_1.24.0-1_amd64.deb
libpcre3_2:8.39-13_amd64.deb
libssl1.1_1.1.1n-0+deb11u5_amd64.deb
...
sudo dpkg -i *.deb
sudo apt -f install # подтянет зависимости из локальных .deb
Можно превратить папку в локальный APT-репозиторий:
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
и подключить его через sources.list.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁18🗿2🔥1
Одновременный запуск команд на нескольких хостах
Иногда нужно быстро выполнить одну и ту же команду на нескольких серверах. Удобные тулзы для этого есть (например, pssh, ansible), но что если хочется сделать это в чистом bash, без сторонних зависимостей? Попробуем реализовать, основная идея такова:
📍 список хостов хранится в текстовом файле;
📍 скрипт пробегает по ним циклом и запускает команду через ssh;
📍 чтобы все шло параллельно - используем background (&) и ограничитель числа потоков.
🛠 Пример скрипта
▪️ Пример hosts.txt
▪️ Запуск
Вывод будет помечен [host], чтобы не путались строки.
BashTex📱 #bash
Иногда нужно быстро выполнить одну и ту же команду на нескольких серверах. Удобные тулзы для этого есть (например, pssh, ansible), но что если хочется сделать это в чистом bash, без сторонних зависимостей? Попробуем реализовать, основная идея такова:
#!/bin/bash
# parallel-ssh.sh
# Одновременное выполнение команд на хостах
HOSTFILE="hosts.txt"
CMD="$*"
MAX_PARALLEL=5 # ограничение параллельных подключений
if [[ -z "$CMD" ]]; then
echo "Использование: $0 'команда для выполнения'"
exit 1
fi
sem=0
while read -r host; do
[[ -z "$host" || "$host" =~ ^# ]] && continue
{
echo ">>> [$host]"
ssh -o BatchMode=yes -o ConnectTimeout=5 "$host" "$CMD" 2>&1 | sed "s/^/[$host] /"
} &
((sem++))
if (( sem >= MAX_PARALLEL )); then
wait -n
((sem--))
fi
done < "$HOSTFILE"
wait
server1
192.168.1.12
192.168.1.15
./parallel-ssh.sh "uptime"
Вывод будет помечен [host], чтобы не путались строки.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Автоматическое формирование changelog из git-истории
Любой проект со временем обрастает десятками коммитов. Но превращать историю git log в читаемый changelog руками - занятие неблагодарное. Bash и git позволяют автоматизировать это в пару строк.
🛠 Базовый скрипт
▪️ Пример вывода
▪️ Можно также добавить:
📍 добавить дату релиза: --date=short --pretty=format:"- %s (%an, %ad)";
📍 разделить по типам коммитов (feat, fix, docs) с помощью grep;
📍 генерировать changelog только для новых коммитов с последнего релиза.
BashTex📱 #bash
Любой проект со временем обрастает десятками коммитов. Но превращать историю git log в читаемый changelog руками - занятие неблагодарное. Bash и git позволяют автоматизировать это в пару строк.
#!/bin/bash
# gen-changelog.sh
OUTFILE="CHANGELOG.md"
{
echo "# Changelog"
echo
# Перебираем теги в обратном порядке
for tag in $(git tag --sort=-creatordate); do
prev=$(git describe --tags --abbrev=0 "$tag"^ 2>/dev/null || echo "")
echo "## $tag"
echo
if [[ -n "$prev" ]]; then
range="$prev..$tag"
else
range="$tag"
fi
git log --pretty=format:"- %s (%an)" "$range"
echo -e "\n"
done
} > "$OUTFILE"
echo "Changelog обновлен: $OUTFILE"
# Changelog
## v2.2.0
- Добавлены новые баги (Ivan)
- Исправлен баг с путями (Anna)
## v2.1.0
- Рефакторинг логики загрузки (Ivan)
- Улучшена работа с сетью (Petr)
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Скрипт для массового обновления SSH-ключей пользователей на кластере
Когда у вас десятки серверов и несколько пользователей, ручное обновление
🛠 Пример скрипта
▪️ Что делает скрипт
📍 перебирает все хосты из hosts.txt;
📍 для каждого пользователя заливает новый authorized_keys;
📍 выставляет правильные права (700 для .ssh, 600 для ключа);
📍 пишет лог успешных и неудачных обновлений.
BashTex📱 #bash
Когда у вас десятки серверов и несколько пользователей, ручное обновление
~/.ssh/authorized_keys превращается в кошмар. Чтобы централизованно обновить ключи (например, при ротации), скрипт может взять все под контроль.Наш скрипт будет:📍 Хранить эталонные ключи пользователей в центральном репозитории (например, /srv/ssh-keys/ или в Git).📍 Проходить по списку хостов и обновлять authorized_keys.📍 Логировать успехи и ошибки.
#!/bin/bash
HOSTS="hosts.txt" # список серверов: один hostname/ip на строку
USERS="users.txt" # список пользователей: один user на строку
KEYDIR="/srv/ssh-keys" # где лежат эталонные ключи (user.pub)
LOGFILE="ssh_update.log"
while read -r host; do
echo "[*] Обновляем ключи на $host"
for user in $(cat "$USERS"); do
keyfile="$KEYDIR/$user.pub"
if [[ -f "$keyfile" ]]; then
ssh "$host" "mkdir -p /home/$user/.ssh && \
chmod 700 /home/$user/.ssh && \
cat > /home/$user/.ssh/authorized_keys && \
chmod 600 /home/$user/.ssh/authorized_keys && \
chown -R $user:$user /home/$user/.ssh" \
< "$keyfile"
if [[ $? -eq 0 ]]; then
echo "$(date '+%F %T') OK $user@$host" >> "$LOGFILE"
else
echo "$(date '+%F %T') FAIL $user@$host" >> "$LOGFILE"
fi
else
echo "Нет ключа для $user"
fi
done
done < "$HOSTS"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Использование coproc для работы с асинхронными потоками
Многие знают про & и wait, но есть куда более элегантный инструмент для асинхронной работы -
▪️ Простейший пример
Процесс bc живет, пока вы его не закроете. То есть можно посылать команды и читать ответы несколько раз.
▪️ Практические кейсы
📍 Асинхронные задачи с обратной связью. Можно запускать ping, tcpdump или tail -f в coproc, а потом считывать поток строк построчно:
📍 Фоновый обработчик. Например, пишем строки в процессинг-скрипт:
📍 Несколько процессов. Coproc можно называть:
BashTex📱 #bash #utils
Многие знают про & и wait, но есть куда более элегантный инструмент для асинхронной работы -
coproc. Это встроенная команда, которая запускает процесс в фоне и автоматически подключает к нему двусторонний канал (pipe).❓ Как это работает
coproc создает процесс, у которого:
stdin доступен через дескриптор ${COPROC[1]} (запись в процесс);
stdout доступен через ${COPROC[0]} (чтение из процесса);
имя coproc можно задавать, чтобы управлять несколькими одновременно.
#!/bin/bash
# Запускаем фоновый bc как "асинхронный калькулятор"
coproc CALC { bc -l; }
# Отправляем в stdin команды
echo "2+3" >&"${CALC[1]}"
echo "s(1)" >&"${CALC[1]}"
# Читаем ответы из stdout
read -u "${CALC[0]}" result1
read -u "${CALC[0]}" result2
echo "Результат 1: $result1"
echo "Результат 2: $result2"
Процесс bc живет, пока вы его не закроете. То есть можно посылать команды и читать ответы несколько раз.
coproc PINGER { ping -O 8.8.8.8; }
while read -ru "${PINGER[0]}" line; do
echo "PING: $line"
done
coproc HANDLER { while read line; do echo ">> $line"; done; }
echo "Hello" >&"${HANDLER[1]}"
echo "World" >&"${HANDLER[1]}"
coproc P1 { ping -c2 8.8.8.8; }
coproc P2 { ping -c2 1.1.1.1; }
▪️ Подводные камни
Каналы буферизуются, иногда нужно sleep или stdbuf -oL для построчной работы.
Закрывайте дескрипторы exec {fd}>&-, иначе процесс может висеть.
coproc работает только в bash ≥ 4.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Встраивание мини-HTTP-сервера на netcat + bash (для локальных API)
Иногда хочется быстро поднять легковесный API без Nginx/Apache, чтобы протестировать интеграцию или выдавать системные данные в JSON. Для этого достаточно bash + netcat.
🛠 Минимальный пример
▪️ Запуск
Теперь можно открыть в браузере: https://localhost:8080
▪️ Возможности
📍 отдавать системные метрики:
📍 простой healthcheck для Docker:
📍 мини-API для локальных скриптов (например, статус бэкапа).
Такой подход позволяет собрать сверхлегкий REST-like API прямо из bash - без сторонних веб-фреймворков.
BashTex📱 #bash #utils
Иногда хочется быстро поднять легковесный API без Nginx/Apache, чтобы протестировать интеграцию или выдавать системные данные в JSON. Для этого достаточно bash + netcat.
Общая идея такова:📍 netcat слушает порт (например, 8080);📍 bash скрипт парсит запрос и отвечает заголовками + данными;📍 результат можно использовать для локальных API-запросов (например, мониторинг).
#!/bin/bash
PORT=8080
while true; do
# Принимаем одно соединение
{
# Читаем первую строку HTTP-запроса
read request
echo ">>> $request"
# Отправляем HTTP-ответ
echo -e "HTTP/1.1 200 OK\r"
echo -e "Content-Type: application/json\r"
echo -e "\r"
echo -e '{"status": "ok", "time": "'$(date +%T)'"}'
} | nc -l -p $PORT -q 1
done
chmod +x mini-http.sh
./mini-http.sh
Теперь можно открыть в браузере: https://localhost:8080
echo -e '{"load": "'$(uptime | awk "{print \$10}")'"}'
curl localhost:8080/healthТакой подход позволяет собрать сверхлегкий REST-like API прямо из bash - без сторонних веб-фреймворков.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5
Please open Telegram to view this post
VIEW IN TELEGRAM
😁38👍5🔥1🫡1
Автоматическое создание LVM-снапшотов с очисткой старых копий
LVM (Logical Volume Manager) - это не только удобное управление дисковыми разделами, но и инструмент для снапшотов. С их помощью можно «заморозить» состояние тома, сделать бэкап или провести тестовые изменения. Но если такие снапшоты создавать регулярно, нужно и контролировать их «уборку».
🛠 Пример скрипта
▪️ Как использовать
Положите скрипт, например в
Сделайте его исполняемым:
Добавьте в cron, например, раз в день в 02:00:
BashTex📱 #bash
LVM (Logical Volume Manager) - это не только удобное управление дисковыми разделами, но и инструмент для снапшотов. С их помощью можно «заморозить» состояние тома, сделать бэкап или провести тестовые изменения. Но если такие снапшоты создавать регулярно, нужно и контролировать их «уборку».
#!/bin/bash
VG="vg0" # имя volume group
LV="data" # исходный LV
SNAP_SIZE="2G" # размер снапшота
KEEP=5 # сколько последних снапшотов хранить
DATE=$(date +%Y%m%d-%H%M)
SNAP_NAME="${LV}_snap_${DATE}"
# 1. Создаём снапшот
lvcreate -L "$SNAP_SIZE" -s -n "$SNAP_NAME" "/dev/$VG/$LV"
echo "[+] Snapshot создан: $SNAP_NAME"
# 2. Список снапшотов, сортировка по дате
SNAPS=$(lvs --noheadings -o lv_name $VG | grep "${LV}_snap_" | sort)
# 3. Если снапшотов больше $KEEP - удаляем старые
COUNT=$(echo "$SNAPS" | wc -l)
if (( COUNT > KEEP )); then
REMOVE=$(echo "$SNAPS" | head -n $((COUNT - KEEP)))
for s in $REMOVE; do
echo "[-] Удаляем старый снапшот: $s"
lvremove -f "/dev/$VG/$s"
done
fi
Положите скрипт, например в
/usr/local/bin/auto-lvm-snapshot.shСделайте его исполняемым:
chmod +x /usr/local/bin/auto-lvm-snapshot.sh
Добавьте в cron, например, раз в день в 02:00:
0 2 * * * root /usr/local/bin/auto-lvm-snapshot.sh >> /var/log/lvm-snapshot.log 2>&1
▪️ Важные моменты📍 Снапшоты занимают место: при изменении данных в оригинальном LV они растут. Размер -L должен быть с запасом.📍 Если снапшот «переполнится» - он станет невалидным.📍 Для бэкапа можно монтировать снапшот в отдельный каталог, а после копирования - удалять его.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Продвинутые regex выражения и их подводные камни
В bash оператор [[ string =~ regex ]] дает инструмент для проверки строк по регулярным выражениям. Но у него есть особенности, о которых часто забывают.
▪️ Базовый синтаксис
=~ - оператор сравнения по регулярному выражению (ERE)
без кавычек вокруг regex (!), иначе он станет строкой
▪️ Подводные камни
1️⃣ Кавычки ломают regex
2️⃣ Пробелы в regex → нужно экранировать
3️⃣ Группы и BASH_REMATCH
BASH_REMATCH[0] - вся строка, [1]..[n] — группы.
4️⃣ Regex всегда интерпретируется как ERE (Extended Regex)
+, ?, | работают без \
Но нет поддержки PCRE (\d, \w, lookahead и т.п.)
5️⃣ Неочевидные совпадения из-за пустого паттерна
6️⃣ Вложенные переменные в regex. Если подставлять переменную в regex, лучше использовать () для контроля:
▪️ Полезные приемы
1️⃣ Проверка на число:
2️⃣ Проверка на IPv4:
3️⃣ Проверка на slug (латиница, цифры, дефис):
BashTex📱 #bash
В bash оператор [[ string =~ regex ]] дает инструмент для проверки строк по регулярным выражениям. Но у него есть особенности, о которых часто забывают.
str="user123"
if [[ $str =~ ^user[0-9]+$ ]]; then
echo "Совпало"
else
echo "Нет совпадения"
fi
=~ - оператор сравнения по регулярному выражению (ERE)
без кавычек вокруг regex (!), иначе он станет строкой
[[ $str =~ "^[0-9]+$" ]] # НЕ работает как regex
[[ $str =~ ^[0-9]+$ ]] # правильно
[[ "foo bar" =~ foo\ bar ]] # правильно
str="id=42 user=admin"
if [[ $str =~ id=([0-9]+)\ user=([a-z]+) ]]; then
echo "ID: ${BASH_REMATCH[1]}"
echo "User: ${BASH_REMATCH[2]}"
fi
BASH_REMATCH[0] - вся строка, [1]..[n] — группы.
+, ?, | работают без \
Но нет поддержки PCRE (\d, \w, lookahead и т.п.)
regex="^$" # пустая строка
[[ "abc" =~ $regex ]] && echo "совпало" # неожиданно не совпадает
re="[0-9]{2}"
[[ "2025" =~ ($re) ]] && echo "нашли: ${BASH_REMATCH[1]}"
[[ $x =~ ^[0-9]+$ ]] && echo "число"
[[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && echo "ipv4"
[[ $slug =~ ^[a-z0-9-]+$ ]] || echo "некорректный slug"
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Оптимизация чтения больших файлов
Когда работаешь с большими логами (гигабайты), вопрос «как читать быстрее и без лишнего расхода памяти?» становится критичным. Сегодня рассмотрим два подхода:
▪️ Подход 1: Чтение чанками (построчно или блочно). Классический цикл:
➕ Память не забивается (читается построчно).
➖ Медленно при миллионах строк (много системных вызовов read).
Для ускорения можно читать чанками (например, по 1 МБ):
➕ Гораздо меньше обращений к диску.
➕ Можно параллелить обработку чанков.
➖ Нужно дополнительно резать блоки на строки (grep, awk, cut).
▪️ Подход 2: mapfile / readarray. Современный и удобный способ загрузить файл в массив:
➕ Удобно: сразу доступ по индексам, можно обрабатывать батчами.
➕ Быстро для средних файлов (< 100–200 МБ).
➖ Огромные файлы (> 1 ГБ) забьют память.
Можно ограничить число строк:
А для потоковой обработки чанками:
➕ Работает как буферизация: читаем батчами по N строк.
➕ Ускоряет обработку за счёт снижения количества вызовов read.
В итоге получаем, что:
Для огромных логов (>1 ГБ) → читайте чанками (dd) или батчами (mapfile -n).
Для средних файлов → mapfile дает лучший баланс.
Для онлайн-потоков (tail -f) → старый добрый while read.
BashTex📱 #bash
Когда работаешь с большими логами (гигабайты), вопрос «как читать быстрее и без лишнего расхода памяти?» становится критичным. Сегодня рассмотрим два подхода:
while IFS= read -r line; do
# обработка строки
done < big.log
Для ускорения можно читать чанками (например, по 1 МБ):
while chunk=$(dd bs=1M count=1 status=none); do
# обработка блока текста (можно разбить на строки)
echo "$chunk" | grep "ERROR"
done < big.log
mapfile -t lines < big.log
echo "Первая строка: ${lines[0]}"
Можно ограничить число строк:
mapfile -t -n 1000 lines < big.log # только первые 1000 строк
А для потоковой обработки чанками:
exec 3< big.log
while mapfile -t -n 1000 batch <&3 && ((${#batch[@]})); do
printf '%s\n' "${batch[@]}" | grep "ERROR"
done
exec 3<&-
В итоге получаем, что:
Для огромных логов (>1 ГБ) → читайте чанками (dd) или батчами (mapfile -n).
Для средних файлов → mapfile дает лучший баланс.
Для онлайн-потоков (tail -f) → старый добрый while read.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
systemd timers: сценарии, которые cron не умеет
Часто cron хватает для простого раз в день, но когда расписание становится хитрым - systemd timers выигрывают. Покажу несколько кейсов, которые на cron делать больно, а здесь - просто.
1️⃣ Только в рабочие дни, с 9:00 до 18:00. Хотим, чтобы скрипт мониторинга нагрузки запускался каждые 15 минут в будни, но не ночью и не в выходные:
Mon..Fri - только будни;
09..18/15:00 - каждые 15 минут с 9:00 до 18:00.
Аналог на cron выглядел бы как несколько строк с костылями.
2️⃣ Persistent=true - выполнение пропущенных задач. Задача должна выполняться раз в день, даже если сервер был выключен ночью.
Если сервак в оффлайне, при старте systemd увидит пропущенное выполнение и запустит задачу.
У cron такого поведения нет - выключил машину, задача пропала.
3️⃣ Замороченные расписания - раз в час, но не в обед. Допустим, хотим запускать скрипт синхронизации каждые 60 минут, но исключить обеденный перерыв (с 12 до 13):
Здесь мы задали диапазоны часов с дыркой.
4️⃣ Несколько расписаний для одной задачи. Хочется иметь и ночной запуск (2:00), и дополнительный в пятницу вечером:
В одном таймере можно указать несколько OnCalendar.
5️⃣ Контроль за пропусками и сбоями. Если критичный скрипт не отработал, мы хотим это видеть. Добавим OnFailure:
Если бэкап упадет, то сразу вызовется alert.service (например, отправка сообщения в телегу).
BashTex📱 #bash #utils
Часто cron хватает для простого раз в день, но когда расписание становится хитрым - systemd timers выигрывают. Покажу несколько кейсов, которые на cron делать больно, а здесь - просто.
/etc/systemd/system/load-check.timer
[Timer]
OnCalendar=Mon..Fri *-*-* 09..18/15:00
Mon..Fri - только будни;
09..18/15:00 - каждые 15 минут с 9:00 до 18:00.
Аналог на cron выглядел бы как несколько строк с костылями.
[Timer]
OnCalendar=daily
Persistent=true
Если сервак в оффлайне, при старте systemd увидит пропущенное выполнение и запустит задачу.
У cron такого поведения нет - выключил машину, задача пропала.
[Timer]
OnCalendar=Mon..Fri *-*-* 09..11:00,13..18:00
Здесь мы задали диапазоны часов с дыркой.
[Timer]
OnCalendar=*-*-* 02:00:00
OnCalendar=Fri *-*-* 19:00:00
В одном таймере можно указать несколько OnCalendar.
/etc/systemd/system/backup.service
[Unit]
Description=Nightly backup job
OnFailure=alert.service
Если бэкап упадет, то сразу вызовется alert.service (например, отправка сообщения в телегу).
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍7
Перехват stdout/stderr отдельных функций и подпрограмм
Обычно мы перенаправляем вывод глобально:
▪️ Пример 1. Логирование только stdout функции
stdout (info, debug) уйдет в stdout.log;
stderr (error) появится в терминале.
▪️ Пример 2. Перехват stderr подпрограммы
Ошибки от ls /root попадут в stderr.log, а «done» останется в терминале.
▪️ Пример 3. Отдельный канал для «отладки» внутри функции. Иногда хочется иметь третий тип вывода, помимо stdout/stderr.
Так можно вести невидимый debug-лог параллельно с обычной работой.
▪️ Пример 4. Подмена stdout на время вызова
Прием позволяет временно заменить stdout и потом вернуть его обратно.
BashTex📱 #bash #utils
Обычно мы перенаправляем вывод глобально:
myfunc >out.log 2>err.log. Но что, если нужно внутри скрипта гибко ловить stdout/stderr отдельных функций и даже подпрограмм, не ломая общий вывод? Тут могут помочь динамические файловые дескрипторы через exec {fd}>.
logfile="stdout.log"
myfunc() {
echo "info: started"
echo "debug: internal"
echo "error: fail" >&2
}
exec {fd}> "$logfile" # создаем FD
myfunc 1>&$fd # stdout -> в файл, stderr остаётся на экран
exec {fd}>&- # закрываем FD
stdout (info, debug) уйдет в stdout.log;
stderr (error) появится в терминале.
errlog="stderr.log"
exec {fd}> "$errlog"
{ ls /root; echo "done"; } 2>&$fd
exec {fd}>&-
Ошибки от ls /root попадут в stderr.log, а «done» останется в терминале.
exec {dbg}> debug.log # отдельный канал
mycalc() {
echo "42" # обычный результат
echo "step1 ok" >&$dbg
echo "step2 ok" >&$dbg
}
result=$(mycalc)
echo "result = $result"
exec {dbg}>&-
Так можно вести невидимый debug-лог параллельно с обычной работой.
mycmd() { echo "normal out"; }
{
exec {fd}> redirected.log
mycmd >&$fd
exec {fd}>&-
}
echo "done"
Прием позволяет временно заменить stdout и потом вернуть его обратно.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10
Быстрый поиск и исправление команд из истории
Многие знают, что в bash есть история команд (history, !, !!), но мало кто активно пользуется экспресс-заменой.
▪️ Замена в последней команде: ^old^new
Если вы ввели команду с ошибкой, не нужно её перепечатывать целиком. Просто используйте конструкцию:
Пример:
Bash сам возьмет последнюю команду из истории и заменит в ней sl на ls.
▪️ Более гибкая работа с историей: !
Пример:
▪️ Ctrl+R для интерактивного поиска
нажмите Ctrl+R и начните печатать часть команды - bash покажет совпадение из истории.
Нажимайте Ctrl+R ещё раз, чтобы найти следующее.
BashTex📱 #bash
Многие знают, что в bash есть история команд (history, !, !!), но мало кто активно пользуется экспресс-заменой.
Если вы ввели команду с ошибкой, не нужно её перепечатывать целиком. Просто используйте конструкцию:
^ошибка^правильноПример:
sl -l #неверная команда
bash: sl: command not found
^sl^ls # исправление
ls -l
Bash сам возьмет последнюю команду из истории и заменит в ней sl на ls.
!! - повторяет последнюю команду!ls - повторяет последнюю команду, начинавшуюся с ls!$ - последний аргумент предыдущей команды!* - все аргументы предыдущей командыПример:
tar -xf archive.tar.gz /tmp
cd !$
cd /tmp
нажмите Ctrl+R и начните печатать часть команды - bash покажет совпадение из истории.
Нажимайте Ctrl+R ещё раз, чтобы найти следующее.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8🫡1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁12
Скрипт-сортер медиа по датам
Хаос в папке с фотографиями и видео? Все вперемешку: отпуск 2018-го рядом с мемами 2024-го. Можно навести порядок одним скриптом.
Идея скрипта в том, чтобы он автоматически раскладывал файлы по структуре:
Основание - дата создания файла (или модификации, если EXIF не нужен).
🛠 Скрипт
▪️ Запуск
🌟 Дополнительно
Если нужен EXIF (реальная дата съёмки фото, а не модификации файла) → используем exiftool:
⚠️ Для видео часто EXIF нет, но можно использовать ffprobe (часть ffmpeg) для даты.
Такой скрипт удобно запускать перед бэкапом в облако - сразу порядок в медиатеке.
BashTex📱 #bash
Хаос в папке с фотографиями и видео? Все вперемешку: отпуск 2018-го рядом с мемами 2024-го. Можно навести порядок одним скриптом.
Идея скрипта в том, чтобы он автоматически раскладывал файлы по структуре:
sorted/
├── 2018/
│ ├── 01/
│ └── 07/
├── 2020/
│ ├── 12/
└── 2024/
├── 02/
└── 05/
Основание - дата создания файла (или модификации, если EXIF не нужен).
#!/bin/bash
SRC_DIR=${1:-"./media"} # откуда берем файлы
DST_DIR=${2:-"./sorted"} # куда складываем
mkdir -p "$DST_DIR"
find "$SRC_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.mp4" -o -iname "*.mov" \) | while read -r file; do
# получаем дату модификации файла (год и месяц)
year=$(date -r "$file" +%Y)
month=$(date -r "$file" +%m)
# создаем директорию и переносим
target="$DST_DIR/$year/$month"
mkdir -p "$target"
echo "→ $file → $target/"
mv "$file" "$target/"
done
chmod +x media_sorter.sh
./media_sorter.sh ./Camera ./SortedMedia
Если нужен EXIF (реальная дата съёмки фото, а не модификации файла) → используем exiftool:
exiftool '-FileName<CreateDate' -d "%Y/%m/%Y-%m-%d_%H-%M-%S%%-c.%%e" ./media
Такой скрипт удобно запускать перед бэкапом в облако - сразу порядок в медиатеке.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Множественные команды одной строкой
Одна из недооцененных фич bash - фигурные скобки {}. Она позволяет за одну строку сгенерировать множество вариантов команды.
▪️ Пример с файлами
Создаст сразу три файла:
▪️ Полезные варианты
1️⃣ Диапазоны чисел
Создаст папки:
2️⃣ Диапазоны букв
3️⃣ Комбинации (картезианское произведение)
4️⃣ Множественные команды
Скопирует оба файла за раз.
▪️ Фишки для автоматизации
1️⃣ Генерация тестовых данных:
сразу 100 файлов
2️⃣ Быстрое клонирование директорий:
создаст копию src-backup без лишнего ввода.
3️⃣ Комбинации шаблонов:
сразу раскладывание отчётов по месяцам и годам.
BashTex📱 #bash #utils
Одна из недооцененных фич bash - фигурные скобки {}. Она позволяет за одну строку сгенерировать множество вариантов команды.
touch file-{1,2,3}.md
Создаст сразу три файла:
file-1.md
file-2.md
file-3.md
mkdir backup-{2022..2025}
Создаст папки:
backup-2022 backup-2023 backup-2024 backup-2025
touch part-{a..d}.txt
part-a.txt part-b.txt part-c.txt part-d.txt
echo {dev,staging,prod}-{us,eu,asia}
dev-us staging-us prod-us dev-eu staging-eu prod-eu dev-asia staging-asia prod-asia
cp config.{yml,json} /etc/myapp/
Скопирует оба файла за раз.
touch user-{001..100}.log
сразу 100 файлов
cp -r src{,-backup}
создаст копию src-backup без лишнего ввода.
mv report_{2022..2024}_{01..12}.csv /data/reports/
сразу раскладывание отчётов по месяцам и годам.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
Букмарк-система для директорий
Если вы часто прыгаете между одними и теми же каталогами, держать их пути в голове (или копировать через cd /long/very/deep/path/...) - мучение. Решение: написать мини-систему закладок для директорий.
🛠 Скрипт j (добавьте это в свой ~/.bashrc или ~/.zshrc):
▪️ Использование
Добавить закладку для текущей директории:
сохраняет myproj:
Перейти в закладку:
мгновенный cd в
Удалить закладку:
Посмотреть все закладки:
BashTex📱 #bash
Если вы часто прыгаете между одними и теми же каталогами, держать их пути в голове (или копировать через cd /long/very/deep/path/...) - мучение. Решение: написать мини-систему закладок для директорий.
# Файл для хранения закладок
J_BOOKMARKS=~/.j_bookmarks
# Функция j
j() {
# без аргументов - показать список закладок
if [[ $# -eq 0 ]]; then
cat "$J_BOOKMARKS" 2>/dev/null || echo "Закладок пока нет."
return
fi
case "$1" in
+) # добавить закладку для текущей директории
echo "$2:$(pwd)" >> "$J_BOOKMARKS"
echo "Добавлено: $2 → $(pwd)"
;;
-) # удалить закладку
grep -v "^$2:" "$J_BOOKMARKS" > "$J_BOOKMARKS.tmp" && mv "$J_BOOKMARKS.tmp" "$J_BOOKMARKS"
echo "Удалено: $2"
;;
*) # перейти по метке
local target
target=$(grep "^$1:" "$J_BOOKMARKS" | cut -d: -f2-)
if [[ -n "$target" ]]; then
cd "$target" || echo "Ошибка: нет доступа к $target"
else
echo "Нет закладки: $1"
fi
;;
esac
}
Добавить закладку для текущей директории:
j + myproj
сохраняет myproj:
/home/user/projects/myprojПерейти в закладку:
j myproj
мгновенный cd в
/home/user/projects/myprojУдалить закладку:
j - myproj
Посмотреть все закладки:
j
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10