BashTex | Linux – Telegram
BashTex | Linux
2.5K subscribers
47 photos
9 videos
288 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

Подойдет для разработчиков, системных администраторов и DevOps

Реклама: @dad_admin
Download Telegram
Управление псевдотерминалами

Псевдотерминалы (PTY) - это то, что позволяет запускать оболочки, эмулировать сессии и автоматизировать взаимодействие с CLI-программами, которые ждут ввода. В linux есть несколько инструментов, которые можно использовать для работы с ними.

▪️ noscript - захват сессии в PTY


noscript -q -c "top -n 1" session.log


Команда выполнится в псевдотерминале, а весь вывод будет сохранен, как будто это была обычная интерактивная сессия.

Полезно: для логгирования; обхода нестандартного поведения программ без TTY.

▪️ socat - соединение PTY с чем угодно. Создание виртуальной пары PTY-устройств:


socat -d -d pty,raw,echo=0 pty,raw,echo=0


Это выведет два устройства /dev/pts/X и /dev/pts/Y, которые можно использовать, например, чтобы связать скрипт и программу, как будто они "болтают" друг с другом.

Применения: имитация COM-портов; отладка CLI-программ; организация проброса ввода/вывода.

▪️ expect - автоматизация интерактивных CLI


#!/usr/bin/expect -f

spawn ssh user@host
expect "password:"
send "supersecret\r"
interact


expect ждет определенный вывод и отправляет нужный ввод. Это незаменимо, когда скрипт должен работать с программой, которая не поддерживает аргументы, только ручной ввод.

Когда это нужно?

📍 автоматизация SCP, FTP, SSH при отсутствии ключей;
📍 создание тестов CLI-интерфейсов;
📍 запуск GUI-оберток над TUI-программами;
📍 обход "упрямых" команд, требующих TTY (sudo, passwd, mysql, и др.);

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Создание honeypot-директории с мониторингом через inotify

Honeypot-директория - это ловушка для злоумышленников: специальная папка, куда никто не должен лазить, но если вдруг кто-то туда сунулся - ты узнаешь первым. С помощью inotifywait и bash можно создать простую систему наблюдения за такими "приманками".

1️⃣ Создаем honeypot-директорию


mkdir -p /opt/.honeypot
chmod 700 /opt/.honeypot


Можно добавить туда пару "интересных" файлов: passwords.txt, backup.tar.gz.

2️⃣ Скрипт для мониторинга


#!/bin/bash
WATCH_DIR="/opt/.honeypot"
LOG="/var/log/honeypot_access.log"

inotifywait -m -e access,modify,create,delete "$WATCH_DIR" --format '%T %w %f %e' --timefmt '%F %T' |
while read event; do
echo "[ALERT] $event" >> "$LOG"
echo "[ALERT] Honeypot accessed: $event"
# Можно добавить: уведомление в TG, systemd-notify и т.д.
done


Этот скрипт не завершится, пока не остановлен вручную - запускай как systemd-сервис или в screen/tmux.

Почему это полезно?

📍 Выявление локальных злоумышленников или скомпрометированных процессов;
📍 Алерт при попытке доступа даже от root, если забыли, что это ловушка;
📍 Возможность записывать все действия, включая дату, время и тип события;

BashTex 📱 #bash #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Может найдешь время поговорить о Linux?

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁13🔥5
Рекурсивная замена в файлах через sed без temp-файлов

Иногда нужно заменить строку или шаблон во всех файлах директории, но без создания временных файлов, лишнего мусора и *.bak. Обычно sed -i решает задачу, но как это сделать рекурсивно, да еще и аккуратно?

▪️ Один-liner: заменить http:// на https:// во всех .conf файлах


find . -type f -name "*.conf" -exec sed -i 's|http://|https://|g' {} +


-i делает замену на месте.
{} - текущий файл, + - запускает sed с пакетами файлов (быстрее, чем по одному).

А если sed без -i (например, BSD/macOS)? Тогда делаем замену через perl:


find . -type f -name "*.conf" -exec perl -pi -e 's|http://|https://|g' {} +


Работает без временных файлов и .bak.

▪️ Хочешь dry-run? Добавь -print в find и убери -i:


find . -type f -name "*.conf" -print -exec grep -H 'http://' {} \;


▪️ Рекурсивная замена с маской и шаблоном


PATTERN="TODO"
REPLACE="Done"

find ./src -type f -name "*.txt" -exec sed -i "s/${PATTERN}/${REPLACE}/g" {} +


⭐️ Можно применять для:

📍 массовая правка конфигов;
📍 удаление старых ссылок;
📍 миграция путей или параметров;
📍 зачистка TODO/DEBUG в исходниках.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Ротация логов с датой и размером: гибридный подход

Стандартные утилиты вроде logrotate умеют ротацию по времени или по размеру, но что если нужно оба условия? Например: хочешь сохранять логи по дате, но если они перевалили за 100 МБ - сразу ротация, не дожидаясь полночи.

Создаем лог-файл вида: myapp_YYYYMMDD.log, и если он >100M - переименовываем с суффиксом _overflow.

🛠 Пример скрипта:


#!/bin/bash
LOG_DIR="/var/log/myapp"
MAX_SIZE=$((100 * 1024 * 1024)) # 100 MB
TODAY=$(date +%Y%m%d)
LOG_FILE="${LOG_DIR}/myapp_${TODAY}.log"

mkdir -p "$LOG_DIR"
touch "$LOG_FILE"

# Проверка размера
if [[ -f "$LOG_FILE" ]]; then
FILE_SIZE=$(stat -c%s "$LOG_FILE")
if (( FILE_SIZE > MAX_SIZE )); then
TS=$(date +%H%M%S)
mv "$LOG_FILE" "${LOG_FILE%.log}_overflow_${TS}.log"
touch "$LOG_FILE"
echo "[INFO] Перемещен переполненный лог-файл: ${LOG_FILE%.log}_overflow_${TS}.log"
fi
fi


▪️ Где использовать? В cron, например:

*/10 * * * * /usr/local/bin/rotate-mixed.sh


В systemd timer для более точного контроля

🌟 В итоге получается, что скрипт не ждет полуночи - реагирует на объем, при этом логи всегда по дате и простой, не требует logrotate.conf

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
А как иначе?

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3🫡3😁2
mapfile + grep + process substitution: тройка для работы с потоками

Когда нужно обработать большой поток данных, отфильтровать его и получить доступ к результатам как к массиву - простого grep уже мало. Тут на сцену выходит связка:


mapfile + grep + <(process substitution)


▪️ Цель: передать данные в массив, фильтруя на лету


mapfile -t matched_lines < <(grep "ERROR" /var/log/syslog)


<(…) - создает временный named pipe
grep фильтрует строки по "ERROR"
mapfile -t читает результат построчно в массив matched_lines

▪️ Применение: разбираем большой лог


for line in "${matched_lines[@]}"; do
echo "Найдено: $line"
done


Под капотом нет временных файлов и лишней нагрузки. Всё работает в памяти и построчно, даже с огромными логами.

▪️ Расширение: фильтрация по нескольким условиям


mapfile -t critical < <(grep -E "FATAL|PANIC|OOM" /var/log/app.log)


Или постфильтрация:


mapfile -t filtered < <(some_command | grep -v DEBUG | grep -i error)


▪️ Пример из реального скрипта:


mapfile -t bad_ips < <(awk '{print $1}' access.log | sort | uniq -c | awk '$1 > 100 {print $2}')


В массив bad_ips попадают только IP, сделавшие >100 запросов.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Пингование списка хостов с журналом доступности в csv/json

Хочешь следить за доступностью нескольких серверов и записывать статистику? Bash + ping + немного магии - и у тебя реестр доступности в csv или json, пригодный для дальнейшего анализа или графиков.

▪️ Пример списка хостов (hosts.txt):


8.8.8.8
1.1.1.1
bashtex.com
192.168.0.1


▪️ Скрипт пингует все хосты и сохраняет отчет в CSV:


#!/bin/bash
INPUT="hosts.txt"
OUTPUT="ping_log.csv"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

[[ ! -f "$OUTPUT" ]] && echo "timestamp,host,status,latency_ms" > "$OUTPUT"

while read -r host; do
if [[ -n "$host" ]]; then
PING_OUT=$(ping -c 1 -W 1 "$host" 2>/dev/null)
if [[ $? -eq 0 ]]; then
LATENCY=$(echo "$PING_OUT" | awk -F'=' '/time=/{print $4}' | cut -d' ' -f1)
echo "$DATE,$host,UP,$LATENCY" >> "$OUTPUT"
else
echo "$DATE,$host,DOWN,0" >> "$OUTPUT"
fi
fi
done < "$INPUT"


▪️ Пример вывода ping_log.csv:


timestamp,host,status,latency_ms
2025-06-06 12:30:01,8.8.8.8,UP,24.1
2025-06-06 12:30:01,bashtex.com,DOWN,0


▪️ Хочешь в JSON? Добавь это после цикла:


jq -Rn '
[inputs | split(",") | {timestamp: .[0], host: .[1], status: .[2], latency_ms: .[3]}]
' "$OUTPUT" > ping_log.json


(Понадобится jq, либо можно собрать JSON вручную через echo)

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Автоматическая генерация графиков из логов

Хочешь строить графики без excel и браузеров? Bash + gnuplot дают способ визуализировать логи прямо из терминала.

Рассмотрим: у нас есть csv лог доступности хостов, созданный скриптом мониторинга:


timestamp,host,status,latency_ms
2025-08-09 12:30:01,8.8.8.8,UP,24.1
2025-08-09 12:31:01,8.8.8.8,UP,25.4
2025-08-09 12:32:01,8.8.8.8,DOWN,0
...


Наша цель: Построить график пинга по времени; сохранить его в png; все сделать из одного bash-скрипта

🛠 Скрипт генерации графика


#!/bin/bash
INPUT="ping_log.csv"
OUTPUT="latency_plot.png"
HOST="8.8.8.8"

# Отфильтровать строки для нужного хоста и подготовить данные
awk -F',' -v host="$HOST" '
$2 == host && $3 == "UP" {
print $1, $4
}
' "$INPUT" > temp_data.dat

# Сгенерировать график
gnuplot <<EOF
set terminal png size 900,300
set output "$OUTPUT"
set noscript "Latency for $HOST"
set xdata time
set timefmt "%Y-%m-%d %H:%M:%S"
set format x "%H:%M"
set xlabel "Time"
set ylabel "Latency (ms)"
set grid
plot "temp_data.dat" using 1:2 with linespoints noscript "Ping latency"
EOF

echo "График сохранен в $OUTPUT"


Если добавить реальный cron - будет наглядная история

🌟 Советы

Можно использовать gnuplot с другими логами: нагрузка CPU, объемы логов, системные метрики;
Можно строить сразу несколько графиков: plot ... noscript "A", ... noscript "B";
Поддерживается SVG, PDF, терминал


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👨‍💻1
Разве нужны еще какие-то аргументы?

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁19
Умная упаковка файлов по маске или дате

Сегодня про то, как архивировать файлы выборочно - например, только .log, только старше 3 дней или только те, что совпадают с маской. Будем комбинировать find, xargs и tar.

▪️ Пример 1: Упаковка логов старше 3 дней


find /var/log/myapp -type f -name "*.log" -mtime +3 \
| xargs tar -czf old_logs.tar.gz


find ищет .log, старше 3 дней
xargs передаёт списком в tar
tar упаковывает их в old_logs.tar.gz

▪️ Пример 2: По шаблону имени (например, только report_*.txt)


find ./reports -type f -name "report_*.txt" \
| xargs tar -czf reports_$(date +%Y%m%d).tar.gz


Упакует все отчеты с именами report_*.txt в архив с датой.

▪️ Если имена с пробелами


find . -type f -name "*.csv" -print0 \
| xargs -0 tar -czf data.tar.gz


-print0 и -0 защищают от пробелов и спецсимволов.

▪️ Плюс: Указание имени архива в переменной


ARCHIVE="backup_$(date +%F).tar.gz"
find . -type f -name "*.conf" -mtime -7 \
| xargs tar -czf "$ARCHIVE"


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Реализация цикла с таймаутом ожидания результата и отменой

Polling с таймаутом в bash - когда нужно подождать результат, но не вечно. Идеально подходит для:

📍 Ожидания ответа от API;
📍 Проверки, появился ли файл;
📍 Проверки, поднялся ли сервис;
📍 Паузы перед перезапуском, если условие не выполнено.

1️⃣ Пример: ждать файл не больше 10 секунд


TIMEOUT=10
INTERVAL=1
FILE="/tmp/ready.flag"

for ((i=0; i<TIMEOUT; i+=INTERVAL)); do
if [[ -f "$FILE" ]]; then
echo "Файл найден"
break
fi
sleep "$INTERVAL"
done

if [[ ! -f "$FILE" ]]; then
echo "Таймаут: файл не появился"
fi


2️⃣ Пример: проверка доступности порта (через nc)


HOST="localhost"
PORT=8080
TIMEOUT=15

for ((i=0; i<TIMEOUT; i++)); do
if nc -z "$HOST" "$PORT"; then
echo "Сервис доступен"
break
fi
sleep 1
done

if ! nc -z "$HOST" "$PORT"; then
echo "Сервис не запустился за $TIMEOUT секунд"
fi


3️⃣ Более обобщенная функция


poll_until() {
local timeout=$1
local interval=$2
shift 2
local elapsed=0

while ((elapsed < timeout)); do
if "$@"; then
return 0
fi
sleep "$interval"
((elapsed+=interval))
done
return 1
}


▪️Использование:


poll_until 10 1 curl -sf http://localhost:8080/health || echo "Недоступен"


Polling pattern с ограничением по времени - инструмент, когда “ожидание результата” должно быть контролируемым.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Генерация временных учёток с автоудалением

Временные учетки в linux с автозапретом - удобный способ:

📍 выдать доступ коллеге или заказчику на пару часов;
📍 дать временный SSH-доступ без ручной чистки;
📍 создать пользователя на ограниченное время (в минутах/часах).

▪️ Пример: учетка на 1 час


USER="tempuser"
PASS="$(openssl rand -base64 12)"
TIMEOUT_MIN=60

# Создание пользователя
useradd -m "$USER"
echo "$USER:$PASS" | chpasswd
echo "Учетка $USER создана. Пароль: $PASS"

# Блокировка через timeout
echo "passwd -l $USER && echo '[INFO] $USER заблокирован'" | at now + "$TIMEOUT_MIN" minutes


▪️ Альтернатива: удаление полностью. Если нужно удалить пользователя, а не только заблокировать:


echo "pkill -u $USER; userdel -r $USER" | at now + "$TIMEOUT_MIN" minutes


▪️ Дополнительно: запрет sudo и ограничение SSH

Не добавляйте пользователя в группы типа sudo. Можно ограничить доступ в sshd_config:


Match User tempuser
ForceCommand echo "Временный доступ завершен"
AllowTcpForwarding no
X11Forwarding no


▪️ Оборачивание в скрипт


#!/bin/bash
USER="temp$RANDOM"
PASS="$(openssl rand -base64 10)"
TIMEOUT_MIN=30

useradd -m "$USER"
echo "$USER:$PASS" | chpasswd
echo "Пользователь $USER создан на $TIMEOUT_MIN минут"
echo "Логин: $USER"
echo "Пароль: $PASS"

echo "userdel -r $USER" | at now + "$TIMEOUT_MIN" minutes


BashTex 📱 #bash #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Работа с датами и интервалами времени без внешних утилит

Как работать с датами и временем, если нельзя использовать date, awk, python, jq и т.п. - только встроенные средства? Такое бывает в ограниченных окружениях (initrd, контейнеры, busybox). Что остается? Только POSIX-переменные, арифметика и системный вызов времени через /proc.

▪️ Получение текущего времени в секундах (POSIX timestamp)


now=$(</proc/uptime) # uptime в секундах с долей
timestamp=$(cut -d. -f1 <<< "$now") # отбрасываем дробную часть
echo "Uptime (сек): $timestamp"


Но если доступен Bash ≥ 4.2, можно так:


now=$(printf '%(%s)T\n' -1) # текущий timestamp


▪️ Расчет интервала (например, сколько секунд назад)


start=1721133000
now=$(printf '%(%s)T\n' -1)
delta=$((now - start))
echo "Прошло $delta секунд"


▪️ Преобразование секунд в формат ЧЧ:ММ:СС


secs=9384 # Пример: 2 ч, 36 мин, 24 сек

printf -v hh '%02d' $((secs / 3600))
printf -v mm '%02d' $(((secs % 3600) / 60))
printf -v ss '%02d' $((secs % 60))

echo "$hh:$mm:$ss"


▪️ Проверка "дата в будущем/прошлом"


deadline=1721190000
now=$(printf '%(%s)T\n' -1)

if (( now > deadline )); then
echo "Просрочено"
else
echo "Еще в сроке"
fi


▪️ Простая "через N секунд"


wait_for=$((60 * 5)) # 5 минут
start=$(printf '%(%s)T\n' -1)

while true; do
now=$(printf '%(%s)T\n' -1)
(( now - start >= wait_for )) && break
sleep 1
done

echo "Прошло 5 минут"


▪️ Мини-фреймворк времени без date. Если date нет вообще, можно использовать /proc/uptime как источник времени с начала загрузки. Это полезно в init-сценариях и embedded-системах.


get_now() {
cut -d. -f1 /proc/uptime
}


Даже без date, python и awk можно: считать интервалы, вычислять прошедшее время, форматировать в ЧЧ:ММ:СС, сравнивать сроки и "таймерить". Это помогает писать portable-скрипты под ограниченные окружения.

BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Отправка файлов на удаленный сервер с логированием и проверкой контрольных сумм

Как надежно передавать файлы на сервер: с логом, контрольной суммой и валидацией? Передача файлов - обычная задача, но часто делается без верификации. Добавим автоматический контроль:

▪️ Инструменты

scp / rsync - передача
sha256sum - хеши
ssh - удаленное выполнение
logger / лог-файл - аудит


▪️ Пример: передача и проверка файла


#!/bin/bash

SRC_FILE="/data/backup.tar.gz"
DEST_USER="user"
DEST_HOST="backup.server"
DEST_PATH="/srv/backups/"
LOG="/var/log/file_transfer.log"

FILENAME=$(basename "$SRC_FILE")
CHECKSUM=$(sha256sum "$SRC_FILE" | awk '{print $1}')
STAMP=$(date '+%F %T')

echo "$STAMP : Начата передача $FILENAME" | tee -a "$LOG"

# Отправка файла
scp "$SRC_FILE" "$DEST_USER@$DEST_HOST:$DEST_PATH"

# Проверка хеша на удаленной стороне
REMOTE_SUM=$(ssh "$DEST_USER@$DEST_HOST" "sha256sum '$DEST_PATH/$FILENAME' | awk '{print \$1}'")

# Сравнение и лог
if [[ "$REMOTE_SUM" == "$CHECKSUM" ]]; then
echo "$STAMP : Успешно: $FILENAME передан и проверен" | tee -a "$LOG"
else
echo "$STAMP : Ошибка: контрольные суммы не совпадают!" | tee -a "$LOG"
fi


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍2
😎 Щас все сделаю как надо

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤨6😁3
Как красиво ждать с прогрессом в терминале

Иногда скрипту нужно подождать: пауза перед перезапуском сервиса, таймер перед завершением работы, задержка в цикле. Просто sleep - бывает скучно. Сделаем задержку с индикатором прогресса прямо в терминале.

▪️ Вариант 1: простой таймер с индикатором прогресса


wait_with_progress() {
local seconds=$1
echo -n "Ожидание $seconds сек: ["
for ((i = 0; i < seconds; i++)); do
echo -n "#"
sleep 1
done
echo "] Готово!"
}

wait_with_progress 5


Вывод:


Ожидание 5 сек: [#####] Готово!


▪️ Вариант 2: "бегающий" индикатор во время ожидания


spinner_wait() {
local pid=$!
local delay=0.1
local spinstr='|/-\'
echo -n "Ждем... "
while kill -0 $pid 2>/dev/null; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
echo "Готово!"
}

# Пример: запуск команды с ожиданием
(sleep 5) & spinner_wait


Этот индикатор крутится, пока выполняется команда.

▪️ Вариант 3: таймер обратного отсчета


countdown() {
local sec=$1
while [ $sec -gt 0 ]; do
printf "\rОсталось: %2d сек..." "$sec"
sleep 1
((sec--))
done
echo -e "\rВремя вышло! "
}

countdown 10


Это удобно для сценариев с обратным отсчетом до перезапуска или отката.


⭐️ Также можно использовать tput civis и tput cnorm для скрытия/показа курсора:


tput civis # скрыть
# ...индикатор...
tput cnorm # вернуть


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11
Построение интерактивного CLI-меню с автодополнением и подсказками

Хотите, чтобы ваши скрипты ощущались как полноценные CLI-утилиты? Добавим в них: интерактивное меню, автодополнение (TAB) и встроенные описания/подсказки по командам.

Создадим скрипт с поддержкой команд (подкоманд) и аргументов, а затем подключаем к нему bash completion через complete -F.

▪️ Пример CLI с командами и подсказками


#!/usr/bin/env bash

# --- CLI-команды ---
main() {
local cmd="$1"; shift
case "$cmd" in
start) echo "Запуск сервиса" ;;
stop) echo "Остановка сервиса" ;;
status) echo "Статус сервиса" ;;
help|"") show_help ;;
*) echo "Неизвестная команда: $cmd"; show_help ;;
esac
}

# --- Подсказки ---
show_help() {
cat <<EOF
Доступные команды:
start - Запустить сервис
stop - Остановить сервис
status - Показать статус
help - Показать справку
EOF
}

main "$@"


▪️ Автодополнение через complete -F. Создаем функцию для автодополнения:


_cli_autocomplete() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
opts="start stop status help"

COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
return 0
}

# Подключаем к нашему скрипту
complete -F _cli_autocomplete mycli


Положите этот код в .bashrc или .bash_completion.d/mycli, и автодополнение команд заработает:


$ ./mycli <TAB>
start status stop help


▪️ Описание команд при наведении. Если используете bash-completion, можно интегрировать подсказки в стиле:


complete -o nospace -o default -F _cli_autocomplete mycli


В более продвинутых реализациях можно добавить справку по каждой команде - через compopt, __ltrim_colon_completions, compgen и массив COMPREPLY.

▪️ Рекомендованная структура CLI


mycli
├── bin/
│ ├── start
│ ├── stop
│ ├── status
└── mycli


Такой подход с автозагрузкой команд из bin/ позволяет расширять CLI без изменения основного скрипта.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Оптимизация вложенных циклов и массивов

Вложенные циклы в bash - частая причина медленных скриптов при работе с большими массивами и файлами. Особенно если ты обрабатываешь 10000+ элементов и каждый проход делает grep, awk, cut, cat, sed...

▪️ Антипаттерн


for i in "${list1[@]}"; do
for j in "${list2[@]}"; do
if [[ "$i" == "$j" ]]; then
echo "Match: $i"
fi
done
done


Это O(N²). Если массивы по 10к строк - будет 100 млн сравнений.

▪️ Оптимизация через associative array (Bash 4+)


declare -A lookup

# Заполняем хеш
for item in "${list2[@]}"; do
lookup["$item"]=1
done

# Ищем быстро
for i in "${list1[@]}"; do
if [[ ${lookup["$i"]+found} ]]; then
echo "Match: $i"
fi
done


Это уже O(N). И в 1000 раз быстрее.

▪️ Ускорение чтения данных. Избавляемся от cat в цикле:

Плохо:


while read line; do
cat "$line"
done < files.txt


Лучше:


mapfile -t files < files.txt

for f in "${files[@]}"; do
cat "$f"
done


▪️ Убираем лишние циклы. Когда можно - переноси логику внутрь awk, grep, join, sort -m и т.д.

Пример: пересечение двух файлов без bash-циклов:


sort file1.txt file2.txt | uniq -d


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Bash-модули: подключение и структура библиотек функций

Когда проект разрастается, скрипты превращаются в мешанину повторяющегося кода. Решение - выносить логику в отдельные .sh-файлы и подключать их как модули. Bash позволяет это делать просто и удобно с помощью source.

▪️ Пример структуры проекта:


project/
├── main.sh
├── lib/
│ ├── colors.sh
│ ├── network.sh
│ └── disk.sh


▪️ Как подключать:


#!/bin/bash
# main.sh

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/colors.sh"
source "$SCRIPT_DIR/lib/network.sh"
source "$SCRIPT_DIR/lib/disk.sh"

log_info "Начинаем выполнение..."
check_network
check_disk_usage


▪️ Файл colors.sh:


#!/bin/bash

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

log_info() {
echo -e "${GREEN}[INFO]${NC} $*"
}

log_error() {
echo -e "${RED}[ERROR]${NC} $*"
}


▪️ Файл network.sh:


#!/bin/bash

check_network() {
if ! ping -c1 8.8.8.8 &>/dev/null; then
log_error "Нет подключения к интернету"
else
log_info "Сеть доступна"
fi
}


▪️ Файл disk.sh:


#!/bin/bash

check_disk_usage() {
local usage
usage=$(df / | awk 'NR==2 {print $5}')
log_info "Использование диска: $usage"
}


⭐️ Рекомендации:

📍 Используй SCRIPT_DIR для относительных путей (надежно даже из cron);
📍 Разделяй модули по темам (log.sh, fs.sh, sys.sh и т.д.);
📍 Добавляй set -euo pipefail в main.sh, но не обязательно в модулях - иначе они могут прерывать подключение.


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
Распараллеливание задач с контролем количества потоков

Когда нужно запустить 1000 задач, но не обрушить сервер - важно уметь распараллеливать выполнение с ограничением на количество одновременных процессов. В bash это можно реализовать без внешних утилит вроде parallel.

🌟 Задача: скачать список URL-ов, но не больше N одновременно.

🛠 Пример скрипта:


#!/bin/bash

MAX_JOBS=5
URLS_FILE="urls.txt"

semaphore() {
while (( $(jobs -rp | wc -l) >= MAX_JOBS )); do
sleep 0.5
done
}

process_url() {
local url="$1"
echo "[*] Загрузка $url"
curl -s -o /dev/null "$url" && echo "[+] $url OK" || echo "[-] $url FAIL"
}

while read -r url; do
semaphore
process_url "$url" &
done < "$URLS_FILE"

wait
echo "Все задачи завершены"


▪️ Пояснения:

jobs -rp - выводит только PID активных фоновых задач.
semaphore() - блокирует запуск, если уже выполняется $MAX_JOBS процессов.
wait в конце - ждет завершения всех фоновых заданий.

▪️ Когда использовать:

📍Массовая обработка файлов (сжатие, конвертация).
📍Сканирование сети.
📍Пакетные вычисления или API-запросы.

BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7