BashTex | Linux
2.49K subscribers
44 photos
8 videos
274 links
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.

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

Реклама: @dad_admin
Download Telegram
Когда спрашивают почему я выбрал Linux

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁19
Автоматизация создания пользователя в Linux

Каждый раз настраивать нового юзера вручную - скучно. Особенно если нужно: создать пользователя, выдать sudo, настроить SSH-доступ, прописать алиасы и окружение

🛠 Решается скриптом (create_user.sh):


#!/bin/bash

USERNAME="$1"
PUBKEY_URL="$2" # URL к публичному ключу или путь к файлу

if [[ -z "$USERNAME" || -z "$PUBKEY_URL" ]]; then
echo "Usage: $0 <username> <pubkey_url_or_file>"
exit 1
fi

# 1. Создание пользователя
useradd -m -s /bin/bash "$USERNAME"

# 2. Добавление в sudoers
usermod -aG sudo "$USERNAME"

# 3. Настройка SSH
HOME_DIR="/home/$USERNAME"
mkdir -p "$HOME_DIR/.ssh"
chmod 700 "$HOME_DIR/.ssh"

# Подгружаем ключ
if [[ "$PUBKEY_URL" =~ ^http ]]; then
curl -s "$PUBKEY_URL" -o "$HOME_DIR/.ssh/authorized_keys"
else
cp "$PUBKEY_URL" "$HOME_DIR/.ssh/authorized_keys"
fi

chmod 600 "$HOME_DIR/.ssh/authorized_keys"
chown -R "$USERNAME:$USERNAME" "$HOME_DIR/.ssh"

# 4. Aliases и welcome message
cat <<EOF >> "$HOME_DIR/.bashrc"

# --- Custom Setup ---
alias ll='ls -alF'
alias gs='git status'
echo "Добро пожаловать, $USERNAME!"
EOF

chown "$USERNAME:$USERNAME" "$HOME_DIR/.bashrc"

echo "[+] Пользователь $USERNAME создан и готов к работе!"


▪️ Пример использования:


./create_user.sh dev1 https://example.com/dev1.pub


или


./create_user.sh admin1 ~/.ssh/id_rsa.pub


Скрипт подходит для CI/CD, dev-серверов, временных пользователей или быстрого поднятия окружения в cloud-инстансах.

BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Bash-функции с возможностью изменять аргументы

Когда ты передаешь переменные в функции - по умолчанию это копии, а не ссылки. Но с declare -n (aka nameref) можно менять переменные по ссылке, включая элементы массивов и даже динамические имена переменных.

Что такое nameref?

declare -n ref=имя - создает ссылку на переменную, позволяя функции менять её напрямую.

▪️ Пример: модификация значения по ссылке


modify() {
declare -n ref=$1
ref="Изменено внутри функции"
}

value="Оригинал"
modify value
echo "$value" # Изменено внутри функции


▪️ Пример: изменение массива внутри функции


update_array() {
declare -n arr=$1
arr+=("новый элемент")
}

my_array=("один" "два")
update_array my_array
printf "%s\n" "${my_array[@]}"


Вывод:


один
два
новый элемент


▪️ Комбинирование с итерацией и позиционными аргументами


double_values() {
declare -n numbers=$1
for i in "${!numbers[@]}"; do
numbers[$i]=$((numbers[$i] * 2))
done
}

arr=(10 20 30)
double_values arr
echo "${arr[@]}" # 20 40 60


❗️ Когда использовать nameref?

📍 Когда хочется возвращать несколько значений из функции
📍 Когда работаешь с динамическими именами переменных
📍 Когда пишешь библиотеки/модули на Bash


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Фоновая очередь с приоритетами

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

💎 Используем:

nice - задаем приоритет (-20 самый высокий, 19 - самый низкий)
wait - ждем завершения задач
& - фоновый запуск
массив - очередь


🛠 Пример: динамическая очередь с приоритетами


#!/bin/bash

declare -a QUEUE=(
"sleep 5" # низкий приоритет
"sleep 2" # высокий приоритет
"sleep 4"
)

declare -a PRIORITY=(
10 # nice +10 → ниже приоритет
-5 # nice -5 → выше приоритет
0
)

for i in "${!QUEUE[@]}"; do
echo "[*] Запуск: ${QUEUE[$i]} с приоритетом ${PRIORITY[$i]}"
nice -n "${PRIORITY[$i]}" bash -c "${QUEUE[$i]}" &
done

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


Что это даёт?

📍 Задачи с низким приоритетом будут уступать CPU
📍 Высокоприоритетные задачи получат преимущество при выполнении
📍 wait гарантирует, что мы дождёмся всех процессов


▪️ Расширение: Добавь ограничение количества параллельных задач:


MAX_PARALLEL=3
PIDS=()

for i in "${!QUEUE[@]}"; do
nice -n "${PRIORITY[$i]}" bash -c "${QUEUE[$i]}" &
PIDS+=($!)

if (( ${#PIDS[@]} >= MAX_PARALLEL )); then
wait -n # ждём завершения хотя бы одной задачи
# удалим завершившиеся из списка
for pid in "${PIDS[@]}"; do
if ! kill -0 "$pid" 2>/dev/null; then
PIDS=("${PIDS[@]/$pid}")
fi
done
fi
done

wait


🔥 Такой подход позволяет:

📍 Делать умные очереди задач
📍 Балансировать нагрузку
📍 Экономить ресурсы
📍 Контролировать порядок и параллелизм


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🗿1
Создаем интерактивность в терминале

Когда хочется добавить взаимодействие в скрипт, но без навороченного TUI, достаточно трех команд Bash: read -s, tput, stty. С их помощью можно: скрыть ввод паролей, управлять курсором, отключать echo, обрабатывать клавиши "на лету".

▪️ read -s - скрытый ввод. Используется для ввода пароля:


read -sp "Введите пароль: " password
echo -e "\nПароль получен!"


-s - скрыть, -p - prompt, -e - enable readline, -n - количество символов

▪️ tput - контроль терминала


tput civis # скрыть курсор
tput cnorm # вернуть курсор
tput setaf 2; echo "Зелёный текст"; tput sgr0


Примеры:

setaf - цвет текста (0-7)
setab - цвет фона
cup 5 10 - переместить курсор на строку 5, столбец 10
clear - очистить экран

▪️ stty - контроль поведения терминала


stty -echo # отключить вывод на экран
read username
stty echo # вернуть обратно


Можно использовать и для отключения Ctrl+C, перехвата ввода, таймаутов:


stty intr '' # временно отключить ^C


▪️ Сценарий: простой ввод пароля с маской


read_password() {
prompt="Введите пароль: "
password=""
while IFS= read -rsn1 char; do
[[ $char == $'\0' || $char == $'\n' ]] && break
password+="$char"
echo -n '*'
done
echo
}

read_password


BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥1
Аудит sudo-доступа всех пользователей


#!/bin/bash

echo "[*] Проверка sudo-доступа всех пользователей..."
echo

# Получим список всех shell-пользователей
getent passwd | awk -F: '$7 ~ /bash|sh/ {print $1}' | while read user; do
echo "==> Пользователь: $user"

# Проверим, может ли пользователь использовать sudo
if sudo -lU "$user" &>/dev/null; then
sudo -lU "$user" 2>/dev/null

echo "[!] Потенциальные лазейки:"
sudo -lU "$user" 2>/dev/null | grep NOPASSWD | grep -Ei 'vim|less|more|nano|perl|python|bash|sh|man|awk|find|xargs|tar|scp|rsync|cp'
echo
else
echo "Нет доступа к sudo или пользователь не существует."
echo
fi
done


🔎 Что делает скрипт:

📍 Сканирует всех пользователей с интерактивным shell;
📍 Выводит sudo -l для каждого;
📍 Ищет опасные команды с NOPASSWD, которые могут дать root-доступ.

▪️ Пример опасных конструкций в sudoers:


(user) NOPASSWD: /usr/bin/vim
(user) NOPASSWD: /usr/bin/find / -exec
(user) NOPASSWD: /usr/bin/python3


Такие команды позволяют поднять интерактивный shell от root без ввода пароля - критическая уязвимость, если не контролируется.

BashTex 📱 #bash #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Перенос окружения на другой сервер с возможностью отката

Забудь про ручное копирование. Используй rsync + версионирование, чтобы миграция алиасов, .bashrc, .config, env-переменных прошла чисто и прозрачно.

▪️ Структура. Создадим папку ~/env-backup/ со всеми элементами:


#!/bin/bash
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
BACKUP_DIR=~/env-backup/$TIMESTAMP

mkdir -p "$BACKUP_DIR"

# Экспорт переменных среды
export -p > "$BACKUP_DIR/env.sh"

# Сохраняем bash окружение
cp ~/.bashrc ~/.bash_aliases ~/.profile "$BACKUP_DIR" 2>/dev/null

# Копируем .config (если нужно)
rsync -a --exclude="*/Cache/" ~/.config "$BACKUP_DIR/config" 2>/dev/null

echo "Окружение сохранено в: $BACKUP_DIR"


▪️ Синхронизация на другой сервер


rsync -avz ~/env-backup/ user@new-host:~/env-backup/


На новом сервере:


cd ~/env-backup/YYYYMMDD-HHMMSS/

cp .bashrc .bash_aliases .profile ~/
rsync -a config/ ~/.config/

# Подгружаем переменные среды
source env.sh


▪️ Версионирование. Каждая копия создаётся с уникальным timestamp'ом, и ты всегда можешь:

📍 Вернуться к предыдущей версии;
📍 Отслеживать изменения в алиасах и bash-окружении;
📍 Проверять дифф между окружениями:


diff -u ~/env-backup/20240601-1000/.bashrc ~/env-backup/20240520-0900/.bashrc


🌟 Рекомендация. Добавь в ~/.bashrc:


[[ -f ~/.bash_aliases ]] && source ~/.bash_aliases
[[ -f ~/env-backup/env.sh ]] && source ~/env-backup/env.sh


BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9
Профилирование скрипта: time, PS4, set -x - лог с таймингом каждой строки

🔎 Скрипт тормозит, но где? Чтобы найти бутылочное горлышко в скрипте, нужно понять, какая строка выполняется долго, а не просто смотреть на общее time.

Решение: профилирование через связку:

time - сколько длился весь скрипт
set -x - трассировка всех команд
PS4 + date - лог с таймингом каждой строки

▪️ Пример: логирование с таймингом


#!/bin/bash

LOGFILE=trace.log

# Префикс трассировки: время и строка
export PS4='+ $(date "+%H:%M:%S.%3N") [${BASH_SOURCE##*/}:${LINENO}] '

# Включаем трассировку и направляем в лог
exec 3>&1 4>&2
exec > >(tee "$LOGFILE") 2>&1
set -x

# Тестовые команды
sleep 1
echo "Шаг 1"
sleep 2
echo "Шаг 2"


▪️ Вывод лога trace.log:


+ 12:34:56.001 [script.sh:12] sleep 1
+ 12:34:57.003 [script.sh:13] echo 'Шаг 1'
Шаг 1
+ 12:34:57.004 [script.sh:14] sleep 2
+ 12:34:59.006 [script.sh:15] echo 'Шаг 2'
Шаг 2


Теперь видно, какая команда занимает больше всего времени. Не нужно гадать.

▪️ Добавим time: Если обернуть скрипт:


time ./script.sh


В конце получим:


real 0m3.006s
user 0m0.002s
sys 0m0.004s


🛠 Скрипт: поиск "медленных" команд в логе


#!/bin/bash

LOG=trace.log
THRESHOLD=1.0 # секунды

awk '
/^\+ / {
ts=$2 # + 12:34:56.001
split(ts, a, ":")
split(a[3], b, ".")
sec = a[1]*3600 + a[2]*60 + b[1] + b[2]/1000
cmd = substr($0, index($0, $4))

if (last_sec > 0) {
delta = sec - last_sec
if (delta >= threshold) {
printf "%6.3fs | %s\n", delta, last_cmd
}
}

last_sec = sec
last_cmd = cmd
}
' threshold="$THRESHOLD" "$LOG"


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


1.002s | sleep 1
2.002s | sleep 2


Теперь ты в автомате видишь: какие строки тормозят, а не листаешь лог на глаз.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥4
Одна ошибка и ты ошибся

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17🗿2
Очистка зависших SSH-сессий

Иногда пользователи (или вы сами) забывают выйти с сервера, и сессия остается в статусе idle или stuck, занимая ресурсы, блокируя терминалы и даже мешая обновлениям. Хорошая новость: Bash + w + ps + timeout помогут автоматически завершать такие сессии.

Что считать зависшей сессией?

📍 Бездействие более 30 минут;
📍 Нет активных процессов;
📍 Неиспользуемый TTY;

🛠 Скрипт для автоудаления "спящих" SSH-сессий


#!/bin/bash

# Время бездействия в минутах
IDLE_LIMIT=30

echo "[*] Поиск SSH-сессий, бездействующих более $IDLE_LIMIT минут..."

w -h | awk -v limit="$IDLE_LIMIT" '
{
idle=$5
if (idle ~ /:/) {
split(idle, t, ":")
minutes = t[1]*60 + t[2]
} else if (idle ~ /old/) {
minutes = 999
} else {
minutes = idle + 0
}

if (minutes >= limit) {
print $2 # TTY
}
}
' | while read tty; do
echo "[!] Завершение процессов на $tty"
pkill -KILL -t "$tty"
done


🌟 Как это работает

w -h - список всех интерактивных сессий
awk парсит IDLE-время
pkill -t завершает процессы, связанные с TTY


❗️ Дополнительно:

📍 Добавь в исключения TTY root'а, CI/CD, сервисных пользователей;
📍 В проде лучше сначала логировать, потом - удалять;

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
😁17
Bash и математика

Это почти несовместимо, но стоит подключить утилиту bc - и ты получаешь калькулятор в консоли, поддерживающий: дробные числа, логические выражения, условные операторы, возведение в степень и функции.

▪️ Пример: базовые вычисления


echo "3.14 * 2.5" | bc
# → 7.85


По умолчанию дробные числа - без знаков после запятой. Поэтому:


echo "scale=4; 10 / 3" | bc
# → 3.3333


▪️ Переменные и выражения


a=5.7
b=3.2
echo "scale=2; $a + $b" | bc
# → 8.9


Или сохранить результат:


result=$(echo "scale=3; ($a^2 + $b^2)^0.5" | bc -l)


Флаг -l включает математическую библиотеку с поддержкой sqrt(), s(), c(), l(), e() и т.д.

▪️ Условия и логика


x=2.5
y=4.1

if [[ $(echo "$x < $y" | bc) -eq 1 ]]; then
echo "$x меньше $y"
fi


▪️ Пример: вычисление средней загрузки из логов CPU


total=0
count=0
for val in 1.2 0.8 2.5 1.9; do
total=$(echo "$total + $val" | bc)
count=$((count + 1))
done
avg=$(echo "scale=2; $total / $count" | bc)
echo "Средняя нагрузка: $avg"


🌟 Когда использовать bc:

📍 скрипты мониторинга;
📍 фин. расчёты в bash;
📍 работа с датчиками (температура, напряжение);
📍 вычисление геометрических величин, преобразование координат

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Сканирование домашнего каталога на наличие SSH-ключей и приватных файлов

SSH-ключи и приватные файлы часто забывают почистить после миграций, тестов и копирований. Но забытый id_rsa в чужом $HOME - это потенциальная дыра в безопасности.

Сегодня про то, как быстро просканировать все домашние каталоги на сервере на наличие:

приватных ключей (id_rsa, *.pem, *.key)
конфигураций с доступами (.ssh/config, known_hosts)
подозрительных backup-файлов (*.bak, *.old, *~)

🛠 Скрипт: поиск чувствительных файлов


#!/bin/bash

echo "[*] Поиск приватных SSH-ключей и чувствительных файлов в /home/*"

find /home /root \
-type f \
\( -name "id_rsa" -o -name "*.pem" -o -name "*.key" -o -name "*.bak" -o -name "*.old" -o -name "*~" \) \
-exec ls -lh {} \; 2>/dev/null


⭐️ Расширенная версия: с владельцем и правами


find /home /root \
-type f \
\( -name "id_rsa" -o -name "*.key" -o -name "*.pem" -o -name "*.gpg" \) \
-printf "%M %u %p\n" 2>/dev/null | sort


▪️ Это поможет заметить, если:

📍 приватный ключ лежит с правами 644 - плохо
📍 файл принадлежит не тому пользователю
📍 ключи забыли в общем ~/Downloads/ или ~/Desktop/

BashTex 📱 #bash #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👨‍💻2🔥1
Выявление SUID-бинарей и контроль их изменений

🌟 SUID-файлы в Linux - это потенциальная зона риска. Если злоумышленник сможет изменить или подменить такой бинарник, он может получить права root. Поэтому важно не только найти такие файлы, но и отслеживать их изменения.

SUID (Set User ID) - бит прав, при котором программа выполняется с правами владельца файла, а не вызывающего пользователя.

Типичный пример:


ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 54256 /usr/bin/passwd


SUID-бит (s вместо x) на позиции владельца.

1️⃣Поиск всех SUID-файлов в системе


find / -perm -4000 -type f 2>/dev/null


Добавим форматированный вывод с размером и датой:


find / -perm -4000 -type f -exec ls -lh {} \; 2>/dev/null


2️⃣ Контроль изменений через контрольные суммы. Создадим базовый снимок:


find / -perm -4000 -type f -exec sha256sum {} \; 2>/dev/null > /var/log/suid_baseline.sha


А теперь проверим изменения:


sha256sum -c /var/log/suid_baseline.sha 2>/dev/null | grep -v ': OK'


Все, что отличается от baseline, будет отображено.

▪️ Добавить cron-задачу:


@daily root /usr/local/bin/suid_check.sh >> /var/log/suid_monitor.log


И сам suid_check.sh:


#!/bin/bash

BASELINE="/var/log/suid_baseline.sha"
TMP="/tmp/suid_check.$$"

find / -perm -4000 -type f -exec sha256sum {} \; 2>/dev/null > "$TMP"

diff -u "$BASELINE" "$TMP" && cp "$TMP" "$BASELINE"
rm "$TMP"


BashTex 📱 #bash #security
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Запуск команд от имени другого пользователя через su/sudo без пароля

Иногда нужно запустить команду от другого пользователя - без постоянного ввода пароля. Например:

от имени сервисного пользователя без логина;
в скриптах автоматизации;
при делегировании задач.

Используем sudo с NOPASSWD и su с передачей команды.

1️⃣ Способ: sudo без пароля. Для этого отредактируем sudoers через:


sudo visudo


Добавим строку:


myuser ALL=(targetuser) NOPASSWD: /usr/bin/systemctl restart my-service


Теперь можно запускать:


sudo -u targetuser /usr/bin/systemctl restart my-service


Или сразу выполнять произвольную команду:


sudo -u deployuser /home/deployuser/scripts/deploy.sh


2️⃣ Способ: su без пароля (через sudo-права). Если sudo уже доступен, можно делать:


sudo su - otheruser -c 'echo $HOME'


Это полезно, если нужна изоляция окружения (su - сбрасывает переменные).

▪️ Пример в скрипте:


#!/bin/bash

USER=deploy
CMD="/opt/app/update.sh"

sudo -u "$USER" bash -c "$CMD"


Обязательно ограничь sudo на конкретную команду в sudoers, чтобы избежать эскалации.

🌟 Безопасность:

📍 Не давай NOPASSWD на ALL!
📍 Всегда указывай полный путь к команде
📍 Используй visudo, чтобы не сломать конфигурацию

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Эмуляция очереди и стека в Bash: играем с массивами как в CS101

В bash можно не только писать условия и циклы, но и реализовать базовые структуры данных. Сегодня - очередь (FIFO) и стек (LIFO) - с помощью обычных массивов.

▪️ Стек (LIFO). Последним пришел - первым ушел.


stack=()

# push
stack+=("первый")
stack+=("второй")

# pop
last_index=$(( ${#stack[@]} - 1 ))
echo "POP: ${stack[$last_index]}"
unset 'stack[$last_index]'


После этого в стеке остается только "первый".

▪️ Очередь (FIFO). Первым пришел - первым ушел.


queue=()

# enqueue
queue+=("alpha")
queue+=("beta")

# dequeue
echo "DEQUEUE: ${queue[0]}"
queue=("${queue[@]:1}")


Мы просто “срезаем” массив начиная с элемента 1.

▪️ Пример: обработка задач в очереди


queue=("job1" "job2" "job3")

while [[ ${#queue[@]} -gt 0 ]]; do
task="${queue[0]}"
echo "Processing $task"
queue=("${queue[@]:1}")
done


▪️ Условно реальный стек


push() { stack+=("$1"); }
pop() { echo "${stack[-1]}"; unset 'stack[-1]'; }
peek() { echo "${stack[-1]}"; }


С bash версии 4+ можно использовать [-1] для получения последнего элемента.

🌟 Минусы:

📍 Нет указателей, только пересоздание массива;
📍 Производительность не сравнима с языками типа Python, но работает.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Парсим YAML и TOML в bash без внешних зависимостей

YAML и TOML - популярные форматы конфигураций. Но в чистом bash их разбирать - задача нетривиальная. Особенно если не хочешь тащить yq, shyaml, python и toml-cli.

Разберемся, как выжать максимум из awk, grep, IFS и других стандартных средств.

▪️ YAML (только простые key: value)


parse_yaml() {
grep '^[^#[:space:]].*:' "$1" | awk -F': ' '
NF == 2 { gsub(/"/, "", $2); print $1 "=" $2 }
'
}


Пример:


# config.yaml
port: 8080
host: localhost
debug: true


Вызов:


eval $(parse_yaml config.yaml)

echo "$host:$port" # → localhost:8080


Не поддерживает вложенные уровни и массивы - только flat YAML.

▪️ TOML (ключ=значение)


parse_toml() {
grep -v '^\s*#' "$1" | grep '=' | while IFS='=' read -r key val; do
key=$(echo "$key" | xargs)
val=$(echo "$val" | sed -E 's/^["'\'']//; s/["'\'']$//' | xargs)
echo "$key=$val"
done
}


Пример:


# config.toml
user = "admin"
port = 9000


Вызов:


eval $(parse_toml config.toml)

echo "$user:$port" # → admin:9000


🟩 Преимущества

📍 Легко встраивается в скрипты
📍 Не требует ничего, кроме POSIX-инструментов
📍 Можно логировать значения или сохранять в массивы

🔲 Ограничения

📍 Нет поддержки массивов, вложенных таблиц, якорей
📍 YAML с отступами, списками и вложениями - не обработается

BashTex 📱 #bash
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
В этот раз все будет хорошо

BashTex 📱 #юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
😁15🗿3
Асинхронное логирование bash-скриптов с метками времени

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

Вот асинхронный способ, как это сделать.

▪️ Подход: через mkfifo и фоновый логгер


#!/bin/bash

LOG_FILE="script.log"
PIPE="/tmp/pipe.$$"

# создаем именованный канал
mkfifo "$PIPE"

# логгер: читает из канала, добавляет таймштамп и пишет в файл
tee "$LOG_FILE" < "$PIPE" |
while IFS= read -r line; do
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line"
done &

# перенаправим stdout и stderr скрипта в канал
exec > "$PIPE" 2>&1

# ———————————————
echo "Скрипт стартовал"
sleep 1
echo "Работаем..."
ls /nonexistent/path
echo "Завершено"
# ———————————————

wait
rm "$PIPE"


🌟 Что получаем:

📍 Вывод в терминале с метками времени
📍 Лог сохраняется в файл без stdout-мусора
📍 Работает асинхронно: скрипт не ждёт tee/while
📍 Поддерживает stderr


Файл script.log будет без меток времени - идеально для машинной обработки
На экране - человекочитаемый лог

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12
Self-test для скриптов: проверка зависимостей, путей и прав доступа перед выполнением

Self-test в начале скрипта - это мини-проверка, которая убеждается, что все окружение готово: утилиты установлены, пути доступны, директории пишутся. Без этого легко получить «тихий фэйл». Добавим в скрипт проверку еще до основной логики.

🛠 Пример базового self-test блока


#!/bin/bash

# 💥 Включаем строгий режим
set -euo pipefail

#Список зависимостей
REQUIRED_CMDS=("curl" "jq" "awk")

#Каталоги, которые должны существовать и быть доступны
REQUIRED_DIRS=("/var/log/myapp" "/etc/myapp")

#Проверка утилит
for cmd in "${REQUIRED_CMDS[@]}"; do
command -v "$cmd" >/dev/null 2>&1 || {
echo "Требуется утилита '$cmd', но она не найдена"
exit 1
}
done

#Проверка директорий
for dir in "${REQUIRED_DIRS[@]}"; do
[[ -d "$dir" ]] || {
echo "Каталог $dir не существует"
exit 1
}
[[ -w "$dir" ]] || {
echo "Нет прав на запись в $dir"
exit 1
}
done

#Проверка прав запуска от root (если нужно)
if [[ $EUID -ne 0 ]]; then
echo "Скрипт должен быть запущен от root"
exit 1
fi

echo "Self-test пройден успешно. Продолжаем выполнение..."


Что еще можно проверять?

📍 Наличие переменных окружения
📍 Работу с удаленными API (curl --silent --fail)
📍 Целостность файлов настроек
📍 Доступность сервисов (systemctl is-active)

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