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

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

Реклама: @dad_admin
Download Telegram
tee не только для логов: запись сразу в несколько потоков

Большинство используют tee только для сохранения вывода команды в файл:

command | tee output.log


Но возможности tee этим не ограничиваются. Он позволяет разветвлять поток данных и отправлять его сразу в несколько мест.

▪️Запись в несколько файлов

Например, сохранить один и тот же вывод сразу в два файла:

dmesg | tee kernel.log backup.log >/dev/null


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

▪️Логирование без потери вывода

Если скрипт должен писать лог, но при этом вывод оставаться в терминале:

./backup.sh | tee backup.log


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

▪️Добавление вместо перезаписи

По умолчанию tee перезаписывает файл.
Чтобы дописывать:

echo "Started" | tee -a app.log


Ключ -a работает так же, как >>.

▪️Передача сразу в несколько команд

Вместе с process substitution можно построить разветвление потока:

journalctl -f \
| tee >(grep ERROR > errors.log) \
>(wc -l > count.txt) \
> /dev/null


Теперь один поток одновременно:
фильтруется по ошибкам;
подсчитывается;
может использоваться в других обработчиках.
Команда journalctl при этом запускается только один раз.

▪️Почему это важно

tee - это не просто инструмент для записи логов. Он позволяет строить конвейеры, где один источник данных обслуживает сразу несколько получателей. Это особенно полезно при анализе логов, мониторинге и автоматизации, когда дорого или невозможно повторно запускать исходную команду.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2
Анализ активных UNIX-сокетов: ss -xl и неожиданные IPC-соединения

Когда ищут открытые сервисы на сервере, обычно проверяют TCP и UDP:

ss -tulpn


Но часть процессов вообще не использует сеть. Они общаются через UNIX-сокеты - локальный механизм IPC между процессами.

▪️Посмотреть активные UNIX-сокеты

ss -x


Ключ -x включает UNIX-сокеты.

Чтобы увидеть только ожидающие подключения:

ss -xl


Пример:

u_str LISTEN 0 128 /run/docker.sock


Это означает, что какой-то процесс принимает локальные подключения через этот сокет.

▪️Найти владельца сокета

Добавляем информацию о процессе:

ss -xlp


Пример:

users:(("dockerd",pid=842,fd=7))


Теперь понятно, какой процесс создал точку обмена.

▪️Проверка прав доступа

UNIX-сокет - это файл, поэтому у него есть обычные права:

ls -l /run/docker.sock


Например:

srw-rw---- root docker docker.sock


Группа с правом записи может управлять Docker через этот сокет.

▪️Найти все сокеты на диске

find / -type s 2>/dev/null


Особое внимание:

/tmp
/dev/shm
/home/*


Системные сервисы чаще используют:

/run
/var/run


▪️Посмотреть, кто держит конкретный сокет

Через lsof:

lsof /run/docker.sock


или:

fuser /run/docker.sock


▪️Почему это важно

Открытый TCP-порт виден сразу при сетевом сканировании. UNIX-сокеты остаются внутри системы и часто забываются при аудите.
При проверке сервера стоит смотреть не только наружные соединения, но и локальные каналы связи между процессами: именно там могут находиться Docker API, базы данных, агенты мониторинга и другие сервисы с важными правами доступа.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Поиск файлов с расширенными ACL: getfacl и find для выявления нестандартных прав

В Linux права доступа обычно проверяют через:

ls -l


Но этого недостаточно. Если у файла есть ACL (Access Control List), дополнительный пользователь или группа могут иметь доступ, которого не видно в стандартном выводе.

▪️Проверяем ACL у файла

getfacl /etc/passwd


Обычный вывод:

user::rw-
group::r--
other::r--


Если есть дополнительные правила:

user::rw-
user:backup:r--
group::r--
mask::r--
other::---


Здесь пользователь backup получил отдельное разрешение.

▪️Как найти файлы с ACL

Команда find умеет искать расширенные ACL:

find / -type f -acl 2>/dev/null


Но на многих системах удобнее использовать проверку через getfacl:

find /etc -type f -exec getfacl -p {} \; 2>/dev/null | grep "^user:"


▪️Проверка конкретного каталога

Например, ищем нестандартные права в /srv:

getfacl -R /srv


Обращаем внимание на строки:

user:name:
group:name:


Они показывают дополнительные разрешения.

▪️Удаление лишних ACL

Если доступ больше не нужен:

setfacl -b file.txt


Ключ -b удаляет все дополнительные ACL, оставляя только обычные Unix-права.

▪️Почему ACL часто забывают

Администратор может изменить права:

chmod 600 secret.txt


и считать файл закрытым.

Но если раньше был добавлен ACL:

user:john:r--


пользователь John всё ещё может читать файл.

▪️Почему это важно

ACL полезны для сложных систем с большим количеством пользователей, но они усложняют аудит. При расследовании проблем с доступом всегда нужно проверять не только chmod, но и расширенные правила через getfacl.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Поиск процессов с удалённым исполняемым файлом

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

Такие процессы стоит периодически искать - особенно после обновлений ПО, удаления пакетов или при аудите безопасности.

▪️Быстрая проверка
Исполняемый файл каждого процесса доступен через /proc/<PID>/exe:

ls -l /proc/*/exe 2>/dev/null | grep '(deleted)'


Например:

/proc/2841/exe -> /usr/bin/python3.12 (deleted)


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

▪️Более удобный вариант

С помощью lsof:

lsof | grep '(deleted)'


Команда покажет не только исполняемые файлы, но и удалённые библиотеки, логи и другие объекты, которые всё ещё удерживаются процессами.

▪️Почему это происходит
Типичный сценарий:

apt upgrade


Во время обновления старый бинарник удаляется и заменяется новым. Но уже запущенный процесс продолжает выполнять старую версию из памяти.
Пока сервис не будет перезапущен, он работает с удалённым файлом.

▪️Когда это становится проблемой

Если удерживается исполняемый файл или библиотека - система использует устаревший код.

Если удерживается большой удалённый лог:

/var/log/app.log (deleted)


место на диске не освободится, пока процесс не закроет файл или не завершится.

▪️Какие процессы требуют внимания

Не все записи (deleted) опасны. В первую очередь стоит проверить:
системные сервисы после обновлений;
процессы с удалёнными библиотеками (.so);
файлы в /tmp или /dev/shm, которые продолжают использоваться после удаления.

▪️Почему это важно

Поиск процессов с (deleted) помогает обнаружить сервисы, которые давно требуют перезапуска, понять, почему не освобождается место на диске, и выявить подозрительные процессы, работающие с уже отсутствующими файлами.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Поиск бинарников с Linux Capabilities: getcap -r /

В Linux привилегии процесса не всегда завязаны только на root. Существуют capabilities - отдельные разрешения ядра, которые можно выдавать конкретным бинарникам.

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

▪️Посмотреть capabilities у файла

getcap /usr/bin/ping


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

/usr/bin/ping cap_net_raw=ep


Это означает, что ping имеет право создавать raw-сокеты.

▪️Поиск всех бинарников с capabilities

getcap -r / 2>/dev/null


Команда рекурсивно проверяет файловую систему и показывает файлы с назначенными capabilities.

Пример:

/usr/bin/python3 cap_net_bind_service=ep
/usr/local/bin/app cap_sys_admin=ep


▪️Что означают флаги

Capability может иметь разные состояния:
cap_net_raw=ep
e (effective) — разрешение активно при запуске;
p (permitted) — процесс может его использовать.
Чаще всего встречается комбинация ep.

▪️Некоторые capabilities фактически дают очень широкие возможности:

cap_sys_admin
cap_dac_override
cap_setuid
cap_sys_ptrace


Например:

cap_dac_override позволяет обходить обычные проверки прав файлов;
cap_setuid позволяет менять UID процесса;
cap_sys_ptrace даёт возможность взаимодействовать с другими процессами.

▪️Проверка конкретного процесса

У работающего процесса capabilities находятся здесь:

cat /proc/1234/status | grep Cap


Ядро хранит их в виде битовых масок.

▪️Удаление capability

Если разрешение больше не требуется:

setcap -r /path/to/binary


После этого файл вернётся к обычной модели прав.

▪️Почему это важно

При аудите Linux недостаточно искать только SUID-биты:

find / -perm -4000


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

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проверка изменения списка загруженных модулей ядра: lsmod + сравнение снимков

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

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

▪️Получить текущий список модулей

lsmod


Пример:

Module        Size      Used by
nf_conntrack 176128 1
veth 32768 2


Но для автоматического сравнения лучше сохранить только имена:

lsmod | awk 'NR>1 {print $1}' | sort > modules.current


▪️Создание базового снимка

После установки и настройки сервера можно сохранить эталон:

lsmod | awk 'NR>1 {print $1}' | sort > /var/lib/modules.snapshot


Позже сравнить:

diff /var/lib/modules.snapshot modules.current


▪️Поиск новых модулей

Например:

comm -13 /var/lib/modules.snapshot modules.current


Покажет только то, что появилось после создания снимка.

▪️Проверка загрузки модулей в логах

Ядро пишет события загрузки:

journalctl -k | grep -i module


Или:

dmesg | grep -i module


▪️Кто загрузил модуль?

Информацию о самом модуле можно получить через:

modinfo veth


Покажет:

файл модуля;
автора;
версию;
зависимости.

▪️Почему это важно

Большинство администраторов контролируют процессы и сетевые порты, но забывают про уровень ядра.

Неожиданный модуль может появиться после установки нового ПО, драйвера или изменения конфигурации. Сравнение снимков lsmod помогает быстро увидеть изменения в состоянии ядра и понять, что именно изменилось на сервере.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Проверка процессов с изменённым OOM Score: /proc/*/oom_score_adj

Когда Linux заканчивается память, ядро запускает OOM Killer. Он выбирает процесс для завершения не случайно - решение зависит от внутренней оценки процесса.

Этой оценкой можно управлять через oom_score_adj.

▪️Посмотреть текущий OOM score процесса
У каждого процесса есть файлы в /proc:

cat /proc/$(pidof nginx)/oom_score


И значение корректировки:

cat /proc/$(pidof nginx)/oom_score_adj


oom_score — итоговый рейтинг для OOM Killer.
oom_score_adj — ручная поправка от -1000 до 1000.

▪️Найти процессы с изменённым приоритетом

for f in /proc/[0-9]*/oom_score_adj; do
value=$(cat "$f" 2>/dev/null)

if [ "$value" != "0" ]; then
pid=${f#/proc/}
pid=${pid%/oom_score_adj}
echo "$pid: $value"
fi
done


Если процесс имеет значение отличное от 0, кто-то явно менял его приоритет.

▪️Что означают значения

Например:

-500
Процесс сложнее убить при OOM.
500
Процесс становится более вероятной жертвой.
Особое значение:
-1000
полностью запрещает OOM Killer выбирать этот процесс.

▪️Посмотреть, кто занимает память и имеет высокий приоритет убийства

ps -eo pid,comm,rss,oom_score_adj --sort=-rss | head


Получаем одновременно:

PID;
имя процесса;
потребление памяти;
настройку OOM.

▪️Где это встречается
systemd может задавать параметр прямо в unit:

[Service]
OOMScoreAdjust=-500


Также это часто используют контейнерные системы, чтобы защитить критичные процессы.

▪️Почему это важно

Иногда при расследовании OOM кажется, что ядро “выбрало неправильный процесс”. Но причина может быть в изменённом oom_score_adj.

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

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
caller: определение места вызова функции в Bash

При отладке больших Bash-скриптов часто недостаточно знать, какая функция упала. Нужно понять, откуда именно она была вызвана.

Для этого есть встроенная команда caller.

▪️Базовый пример

function test_func() {
caller
}

test_func


Вывод:
5 main

Это означает: функция была вызвана из 5-й строки функции main (или основного скрипта).

▪️Использование в логировании ошибок

Например, создаём функцию логирования:

log_error() {
echo "Error from:"
caller
}

backup() {
log_error
}

backup


Теперь при ошибке видно не только сообщение, но и источник вызова.

▪️Получение полного стека вызовов

caller умеет подниматься вверх по стеку:

function level3() {
caller 0
caller 1
}

function level2() {
level3
}

function level1() {
level2
}

level1


caller 0 покажет текущий уровень, а caller 1 - предыдущий.

▪️Практический пример с обработчиком ошибок

die() {
echo "Failed at:"
caller
exit 1
}

deploy() {
false || die
}

deploy


Вместо:
Failed
получаем:
Failed at:
12 deploy

Сразу понятно, где искать проблему.

▪️Отличие от $FUNCNAME

В Bash уже есть массивы:
echo "${FUNCNAME[@]}"
Они показывают цепочку функций:

deploy backup main


А caller дополнительно даёт:

номер строки;
имя файла;
контекст вызова.

▪️Где полезно

большие Bash-проекты;
библиотеки функций;
CI/CD-скрипты;
автоматизация с большим количеством уровней вызова.

▪️Почему это важно

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

caller - простой встроенный инструмент, который превращает отладку Bash из поиска по всему файлу в точное указание места проблемы.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
hash: почему Bash иногда запускает “не ту” команду

Каждый раз искать исполняемый файл в каталогах из $PATH было бы дорого. Поэтому Bash запоминает найденные пути в собственном кэше команд.

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

▪️Посмотреть кэш команд

hash


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

hits    command
12 /usr/bin/git
5 /usr/bin/python3
8 /usr/bin/ssh


Здесь видно, какие команды Bash уже нашёл и закэшировал.

▪️Как работает кэш
Допустим, Bash уже знает:

/usr/bin/python3


Но затем появился другой бинарник раньше в $PATH:

/usr/local/bin/python3


Shell может продолжить использовать старый путь, пока кэш не будет обновлён.

▪️Очистить кэш
Полностью:

hash -r


После этого Bash снова выполнит поиск команды по $PATH.

Очистить только одну запись:

hash -d python3


При следующем запуске путь будет найден заново.

▪️Проверить, что реально запустится

type -a python3


или

which -a python3


Это покажет все найденные бинарники, но именно Bash может использовать уже закэшированный путь.

▪️Когда это бывает полезно

Частые ситуации:
• установка новой версии программы в /usr/local/bin;
• изменение $PATH внутри скрипта;
• переключение между несколькими версиями Python, Java или Node.js;
• обновление исполняемых файлов без открытия нового терминала.

▪️Почему это важно

Если после изменения $PATH или установки новой версии команда продолжает запускать старый бинарник, проблема может быть не в переменной окружения, а в кэше Bash.

Одна команда hash -r часто решает проблему быстрее, чем долгий поиск ошибок в конфигурации.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
readarray: читаем вывод команды в массив без циклов

Часто в Bash список файлов или строк читают через while read. Но если нужно просто получить все данные в массив, есть более короткий и быстрый способ - readarray (или его синоним mapfile).

▪️Классический подход

files=()

while IFS= read -r file; do
files+=("$file")
done < <(find /var/log -name "*.log")


Работает, но код получается довольно громоздким.

▪️То же самое через readarray

readarray -t files < <(
find /var/log -name "*.log"
)


Теперь весь вывод команды сразу окажется в массиве files.

▪️Что делает ключ -t

Без него каждый элемент массива будет содержать символ новой строки (\n) в конце.

Практически всегда стоит использовать:

readarray -t lines < file.txt


Так строки попадут в массив уже без лишних символов.

▪️Работа с массивом

Например, узнать количество найденных файлов:

echo "${#files[@]}"


Или пройтись по ним:

for file in "${files[@]}"; do
echo "$file"
done


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

readarray считывает весь поток целиком. Если команда выводит миллионы строк или очень большой файл, массив займёт соответствующий объём памяти.
В таких случаях потоковая обработка через while read остаётся более подходящим вариантом.

▪️Почему это важно

Во многих скриптах while read используется просто по привычке. Если задача - получить список строк для дальнейшей работы, readarray делает то же самое в одну команду, сохраняя код компактным и избавляя от ручного заполнения массива.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
exec: замена процесса без создания дочернего

Обычно при запуске команды Bash создаёт новый процесс:

sleep 60


После завершения sleep управление возвращается обратно в shell.

Но exec работает иначе - он заменяет текущий процесс новым. Старый процесс исчезает, а его PID сохраняется.

▪️Простой пример

echo $$
exec sleep 60


После выполнения вы больше не вернётесь в текущий shell. Процесс Bash будет полностью заменён на sleep.

▪️Почему PID не меняется

Запустим:

echo $$
exec bash


И снова:

echo $$


PID останется тем же. Новый экземпляр Bash не был создан - текущий процесс просто заменился.

▪️Где это действительно полезно

Представьте простой launcher:

#!/bin/bash

echo "Starting application..."
exec /usr/local/bin/myapp


После запуска в системе не останется лишнего процесса Bash - только myapp.

Это особенно важно для:
контейнеров Docker;
systemd-сервисов;
entrypoint-скриптов.

▪️Почему это лучше обычного запуска

Без exec:

bash
└── myapp


С exec:

myapp

Нет промежуточного процесса, сигналы (SIGTERM, SIGINT) сразу получает приложение, а не оболочка.

▪️Когда использовать нельзя

После exec текущий скрипт прекращает существование:

echo "Before"
exec sleep 5
echo "After"


Строка After никогда не выполнится.

▪️Почему это важно

Многие воспринимают exec как ещё один способ запуска команды. На самом деле это механизм замены процесса. Он позволяет убрать лишний уровень в дереве процессов, избежать проблем с обработкой сигналов и сделать запуск сервисов более предсказуемым.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍1🗿1
find -exec против -exec {} +: почему одна команда может быть в десятки раз быстрее

Многие используют find так:

find /var/log -name "*.log" -exec gzip {} \;


Команда работает, но есть нюанс: для каждого найденного файла запускается отдельный процесс gzip.

▪️Что происходит

Если найдено 5000 файлов, Bash выполнит примерно 5000 запусков gzip.

Это лишние создания процессов, переключения контекста и заметная потеря производительности.

▪️Более эффективный вариант

find /var/log -name "*.log" -exec gzip {} +


Теперь find собирает несколько файлов и передаёт их одной команде:

gzip file1.log file2.log file3.log ...


Количество запусков сокращается в десятки или даже сотни раз.

▪️В чём разница

Вариант с \;:

gzip file1
gzip file2
gzip file3


Вариант с +:

gzip file1 file2 file3


Логика обработки не меняется, но накладные расходы становятся значительно меньше.

▪️Когда + использовать нельзя

Если команда должна выполняться отдельно для каждого файла, например:

find . -type f -exec mv {} {}.bak \;


или внутри используется сложная оболочка:

find . -type f -exec sh -c '...' \;


В таких случаях объединение аргументов может изменить поведение команды.

▪️Как выбрать

Используйте -exec {} +, когда команда умеет принимать сразу несколько файлов:

rm
chmod
chown
gzip
cp
mv (при копировании в каталог)
ls


Если же обработка должна происходить строго по одному файлу — остаётся -exec {} \;.

▪️Почему это важно

Во многих скриптах find -exec {} \; используется по привычке. Замена всего одного символа — \; на + - позволяет значительно сократить число создаваемых процессов и ускорить обработку больших каталогов без изменения логики скрипта.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2
env -i: запуск программы в полностью “чистом” окружении

Большинство программ наследуют десятки переменных окружения: PATH, HOME, LANG, LD_LIBRARY_PATH, прокси, токены и многое другое.
Иногда именно они становятся причиной странного поведения приложения.

▪️Посмотреть текущее окружение

env
или:
printenv


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

▪️Запуск без окружения

Команда:

env -i bash


запустит новый Bash практически без переменных окружения.
Если выполнить:
env
вывод окажется пустым или почти пустым.

▪️Передать только нужные переменные

Например:

env -i PATH=/usr/bin:/bin HOME=/tmp bash


Теперь программа получит только PATH и HOME.
Это особенно удобно при поиске ошибок.

▪️Практический пример

Есть скрипт:

./deploy.sh


У одного пользователя он работает, у другого - нет.

Проверяем:

env -i PATH=/usr/bin:/bin ./deploy.sh


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

▪️Где ещё используется

• отладка CI/CD;
• проверка зависимостей от окружения;
• запуск сервисов в предсказуемых условиях;
• поиск проблем с PATH, LANG, HOME и прокси.

▪️Почему это важно

Ошибки, связанные с окружением, часто трудно воспроизвести: скрипт работает у одного администратора и ломается у другого. env -i позволяет полностью исключить влияние наследуемых переменных и быстро понять, зависит ли программа от окружения больше, чем кажется.

BashTex 📱 #bash #linux
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Forwarded from localhost
Media is too big
VIEW IN TELEGRAM
С ДНЕМ СИСАДМИНА! 👍

По традиции в этот великий день мы смотрим классику 🎬

😎 localhost › IT-юмор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Когда переменные пропадают

Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.

▪️ Что такое subshell. Subshell - это дочерний процесс bash. Он получает копию переменных, но изменения не возвращаются назад. Создается, например, здесь:


( command )


или в пайпах:


command | while read ...


▪️ Классическая проблема


count=0

echo -e "a\nb\nc" | while read -r line; do
((count++))
done

echo "$count"


Результат: 0

Почему? Цикл while выполняется в subshell.

▪️ Правильный вариант


count=0

while read -r line; do
((count++))
done < <(echo -e "a\nb\nc")

echo "$count"


Результат: 3

Теперь цикл работает в текущем shell.

▪️ Ещё пример


x=1

( x=5 )

echo "$x"


Результат: 1
Изменение потерялось.

▪️ Когда это полезно. Subshell - это не баг, а инструмент. Например:


( cd /tmp && ls )


внутри меняем каталог, а снаружи остаемся там же

BashTex 📱 #scripts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
mkfifo: обмен данными между процессами через именованные каналы

Обычный pipe:

command1 | command2


работает только пока запущены обе команды. Но иногда нужен постоянный канал, к которому разные процессы могут подключаться позже.

Для этого в Linux есть FIFO (named pipe).

▪️Создание именованного канала

mkfifo /tmp/my_pipe


Теперь /tmp/my_pipe выглядит как файл:

ls -l /tmp/my_pipe


Вывод:

prw-r--r-- 1 user user 0 Aug 4 12:00 my_pipe


Буква p означает pipe.

▪️Передача данных между двумя процессами

Терминал 1:

cat /tmp/my_pipe


Терминал 2:

echo "hello from process" > /tmp/my_pipe


Первый процесс сразу получит сообщение.

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

Можно отправлять события из одного скрипта в другой:

mkfifo /tmp/events.pipe

tail -f /var/log/app.log > /tmp/events.pipe &


А отдельный обработчик:

while read line; do
echo "EVENT: $line"
done < /tmp/events.pipe


Теперь обработка логов отделена от источника данных.

▪️Важный момент
FIFO блокирует процесс:

echo "data" > /tmp/my_pipe


будет ждать, пока кто-то откроет канал на чтение.

Поэтому в автоматизации часто используют фоновые процессы:

cat /tmp/my_pipe &
echo "start" > /tmp/my_pipe


▪️Чем отличается от обычного файла

Данные в FIFO не сохраняются на диске.
Если никто не читает:
процесс → FIFO → процесс
данные не складываются в очередь, а ждут получателя.

▪️Где полезно

• связь между Bash-скриптами;
• простые IPC-механизмы;
• обработка потоков данных;
• разделение генератора и обработчика.

▪️Почему это важно

mkfifo часто заменяет временные файлы и сложные конструкции с перенаправлениями. Это простой способ построить связь между независимыми процессами прямо средствами Linux без дополнительных сервисов.

BashTex 📱 #mfifo
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Почему sort | uniq не всегда работает так, как ожидается

Когда нужно убрать дубликаты, многие сразу пишут:

sort file.txt | uniq


Работает. Но только если понимать, что именно делает каждая команда.

▪️Как работает uniq

Распространённое заблуждение - uniq ищет все повторяющиеся строки.

На самом деле он удаляет только соседние дубликаты.

Например:

apple
banana
apple
orange


Если выполнить:

uniq file.txt


получим тот же самый список - одинаковые строки не стоят рядом.

▪️Зачем нужен sort

После сортировки одинаковые строки оказываются соседними:

sort file.txt | uniq


Результат:

apple
banana
orange


Именно поэтому эти команды почти всегда используются вместе.

▪️Когда сортировка не подходит

Если порядок строк важен, sort изменит его.
Например, при анализе логов или событий по времени это может полностью исказить картину.

В таких случаях лучше использовать:

awk '!seen[$0]++'


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

▪️Найти только повторяющиеся строки

Иногда нужны не уникальные записи, а наоборот - только дубликаты:

sort file.txt | uniq -d


Или вывести количество повторений:

sort file.txt | uniq -c


Получим:

15 nginx
8 sshd
3 cron


▪️Почему это важно

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

BashTex 📱 #sort
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Проверка доступности локальных Unix-сервисов: nc -U и curl --unix-socket

Не все сервисы в Linux слушают TCP-порты. Многие приложения работают только через UNIX-сокеты - локальные каналы связи между процессами.

Например:

/run/docker.sock
/run/php/php-fpm.sock
/run/containerd/containerd.sock


Снаружи такие сервисы не видны через обычный nmap, но внутри системы они могут иметь важное значение.

▪️Найти активные UNIX-сокеты

ss -xl


Пример:

u_str LISTEN 0 128 /run/docker.sock


Теперь можно проверить, отвечает ли сервис.

▪️Проверка через nc

Netcat умеет подключаться к UNIX-сокетам:

nc -U /run/docker.sock


Если соединение установлено - сокет доступен.

Для HTTP-сервисов можно отправить запрос вручную:

printf "GET / HTTP/1.0\r\n\r\n" | nc -U /run/service.sock


▪️Проверка HTTP API через curl

Многие локальные API работают через UNIX-сокеты:

curl --unix-socket /run/docker.sock http://localhost/version


Здесь localhost не используется как сетевой адрес - он нужен только для формирования HTTP-запроса.

▪️Пример с Docker

Вместо:

docker version


можно напрямую обратиться к API:

curl --unix-socket /var/run/docker.sock \
http://localhost/_ping


Ответ:

OK


означает, что Docker daemon доступен.

▪️Проверка прав доступа

Даже если сервис работает, доступ может быть ограничен:

ls -l /run/docker.sock


Например:

srw-rw---- root docker docker.sock


Только пользователи группы docker смогут подключиться.

▪️Почему это важно

UNIX-сокеты часто остаются вне стандартного мониторинга. Администратор проверяет открытые порты, но забывает про локальные API и IPC-каналы.

Проверка через ss, nc -U и curl --unix-socket помогает быстро понять:
жив ли сервис;
кто имеет к нему доступ;
отвечает ли локальное API;
нет ли неожиданного открытого канала между процессами.

BashTex 📱 #sort
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
eval: почему опасен и когда реально нужен

В Bash почти любую строку можно превратить в команду через eval. Он берёт переданный текст и запускает его как новый Bash-код.

Именно поэтому это один из самых спорных инструментов в shell-скриптах.

▪️Как работает eval

Простой пример:

cmd="ls -la"

eval "$cmd"


Bash сначала получает строку:

ls -la


а затем выполняет её как обычную команду.

▪️Где возникает проблема

Если данные приходят от пользователя:
read input

eval "$input"


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

Главная проблема eval - повторный разбор данных как команд.

▪️Почему кавычки не всегда спасают

Например:

file="test.txt"

eval "cat $file"


Пока значение простое - всё работает.

Но если внутри появятся специальные символы:
file="file name.txt"
или другие управляющие конструкции, поведение может отличаться от ожидаемого.

▪️Частая замена eval

Вместо хранения команды строкой:

cmd="ls -la /tmp"
eval "$cmd"


лучше использовать массив:

cmd=(ls -la /tmp)

"${cmd[@]}"


Теперь Bash хранит команду и аргументы отдельно.

▪️Когда eval действительно нужен

Иногда без него сложно обойтись. Например, при работе с динамическими именами переменных:
name="USER"

eval "echo \$$name"


Но даже здесь часто есть более безопасные варианты:

declare -n ref="$name"
echo "$ref"


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

Если всё же нужен eval, данные должны быть полностью контролируемыми:

case "$action" in
start|stop|restart)
eval "service_$action"
;;
esac


Здесь значение ограничено заранее известным списком.

▪️Почему это важно

eval не является “плохой” командой сам по себе. Проблема появляется, когда данные превращаются в код.
В большинстве случаев массивы, case, функции или declare решают задачу безопаснее. eval стоит оставлять только для ситуаций, где действительно нужен второй проход парсинга Bash.

BashTex 📱 #eval
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Проверка времени отклика сервисов

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

▪️ Самый простой замер


time curl -s https://bashtex.com > /dev/null


Показывает общее время выполнения запроса и быстро понять, тормозит или нет.

▪️ Точнее: только сетевое время


curl -s -o /dev/null -w "time_total: %{time_total}\n" https://bashtex.com


Полезные метрики:

time_namelookup
time_connect
time_starttransfer
time_total

Пример:


curl -w "DNS:%{time_namelookup} CONNECT:%{time_connect} TTFB:%{time_starttransfer} TOTAL:%{time_total}\n" \
-o /dev/null -s https://bashtex.com


▪️ Проверка нескольких сервисов


for url in https://a.ru https://b.ru; do
curl -o /dev/null -s -w "$url %{time_total}\n" "$url"
done


▪️ Таймаут обязателен


curl --connect-timeout 3 --max-time 5 https://bashtex.com


Без таймаута любой мониторинг бесполезен.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
PIPESTATUS: как узнать, какая команда в пайпе реально упала

В Bash есть неприятная особенность: после пайпа $? показывает статус только последней команды.

Например:

false | grep test

echo $?


Здесь grep успешно отработал и вернул 0, поэтому ошибка false потерялась.

▪️На помощь приходит PIPESTATUS

Сразу после выполнения пайпа:

false | grep test

echo "${PIPESTATUS[@]}"


Получим:

1 1


Каждое значение соответствует своей команде.

false       → 1
grep test → 1


▪️Более наглядный пример

cat /missing/file | grep ERROR | sort

echo "${PIPESTATUS[@]}"


Можно получить:

1 1 0


То есть cat завершился с ошибкой, grep ничего не получил, а sort технически выполнился успешно.

▪️Важный нюанс

PIPESTATUS очень легко потерять:

false | true

echo "${PIPESTATUS[@]}"


работает.

Но если между пайпом и проверкой выполнить другую команду:

false | true

echo "check"
echo "${PIPESTATUS[@]}"


теперь PIPESTATUS относится уже к echo "check".

Поэтому сохраняйте его сразу:

false | true

status=("${PIPESTATUS[@]}")

echo "${status[@]}"


▪️А если нужен общий статус пайпа?

Есть:

set -o pipefail


Теперь:

false | true

echo $?


вернёт ненулевой код.

Но pipefail отвечает только на вопрос «пайп завершился успешно?», а PIPESTATUS позволяет понять «какая именно команда вернула ошибку?».

▪️Почему это важно

В сложных Bash-конвейерах последняя команда может успешно завершиться даже тогда, когда предыдущая уже упала. PIPESTATUS позволяет не терять эти ошибки и точно определить проблемный этап.

BashTex 📱 #bash #utils
Please open Telegram to view this post
VIEW IN TELEGRAM
👨‍💻4